afb-api-js: first step for javascript bindings
[src/app-framework-binder.git] / src / duktape.c
1 /*
2  *  Single source autogenerated distributable for Duktape 2.3.0.
3  *
4  *  Git commit d7fdb67f18561a50e06bafd196c6b423af9ad6fe (v2.3.0).
5  *  Git branch master.
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-2018 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 *
99 *  Other contributions
100 *  ===================
101 *
102 *  The following people have contributed something other than code (e.g. reported
103 *  bugs, provided ideas, etc; roughly in order of appearance):
104 *
105 *  * Greg Burns
106 *  * Anthony Rabine
107 *  * Carlos Costa
108 *  * Aur\u00e9lien Bouilland
109 *  * Preet Desai (Pris Matic)
110 *  * judofyr (http://www.reddit.com/user/judofyr)
111 *  * Jason Woofenden
112 *  * Micha\u0142 Przyby\u015b
113 *  * Anthony Howe
114 *  * Conrad Pankoff
115 *  * Jim Schimpf
116 *  * Rajaran Gaunker (https://github.com/zimbabao)
117 *  * Andreas \u00d6man
118 *  * Doug Sanden
119 *  * Josh Engebretson (https://github.com/JoshEngebretson)
120 *  * Remo Eichenberger (https://github.com/remoe)
121 *  * Mamod Mehyar (https://github.com/mamod)
122 *  * David Demelier (https://github.com/markand)
123 *  * Tim Caswell (https://github.com/creationix)
124 *  * Mitchell Blank Jr (https://github.com/mitchblank)
125 *  * https://github.com/yushli
126 *  * Seo Sanghyeon (https://github.com/sanxiyn)
127 *  * Han ChoongWoo (https://github.com/tunz)
128 *  * Joshua Peek (https://github.com/josh)
129 *  * Bruce E. Pascoe (https://github.com/fatcerberus)
130 *  * https://github.com/Kelledin
131 *  * https://github.com/sstruchtrup
132 *  * Michael Drake (https://github.com/tlsa)
133 *  * https://github.com/chris-y
134 *  * Laurent Zubiaur (https://github.com/lzubiaur)
135 *  * Neil Kolban (https://github.com/nkolban)
136 *  * Wilhelm Wanecek (https://github.com/wanecek)
137 *  * Andrew Janke (https://github.com/apjanke)
138 *
139 *  If you are accidentally missing from this list, send me an e-mail
140 *  (``sami.vaarala@iki.fi``) and I'll fix the omission.
141 */
142
143 #line 1 "duk_replacements.c"
144 /*
145  *  Replacements for missing platform functions.
146  *
147  *  Unlike the originals, fpclassify() and signbit() replacements don't
148  *  work on any floating point types, only doubles.  The C typing here
149  *  mimics the standard prototypes.
150  */
151
152 /* #include duk_internal.h */
153 #line 1 "duk_internal.h"
154 /*
155  *  Top-level include file to be used for all (internal) source files.
156  *
157  *  Source files should not include individual header files, as they
158  *  have not been designed to be individually included.
159  */
160
161 #if !defined(DUK_INTERNAL_H_INCLUDED)
162 #define DUK_INTERNAL_H_INCLUDED
163
164 /*
165  *  The 'duktape.h' header provides the public API, but also handles all
166  *  compiler and platform specific feature detection, Duktape feature
167  *  resolution, inclusion of system headers, etc.  These have been merged
168  *  because the public API is also dependent on e.g. detecting appropriate
169  *  C types which is quite platform/compiler specific especially for a non-C99
170  *  build.  The public API is also dependent on the resolved feature set.
171  *
172  *  Some actions taken by the merged header (such as including system headers)
173  *  are not appropriate for building a user application.  The define
174  *  DUK_COMPILING_DUKTAPE allows the merged header to skip/include some
175  *  sections depending on what is being built.
176  */
177
178 #define DUK_COMPILING_DUKTAPE
179 #include "duktape.h"
180
181 /*
182  *  User declarations, e.g. prototypes for user functions used by Duktape
183  *  macros.
184  */
185
186 DUK_USE_USER_DECLARE()
187
188 /*
189  *  Duktape includes (other than duk_features.h)
190  *
191  *  The header files expect to be included in an order which satisfies header
192  *  dependencies correctly (the headers themselves don't include any other
193  *  includes).  Forward declarations are used to break circular struct/typedef
194  *  dependencies.
195  */
196
197 /* #include duk_dblunion.h */
198 #line 1 "duk_dblunion.h"
199 /*
200  *  Union to access IEEE double memory representation, indexes for double
201  *  memory representation, and some macros for double manipulation.
202  *
203  *  Also used by packed duk_tval.  Use a union for bit manipulation to
204  *  minimize aliasing issues in practice.  The C99 standard does not
205  *  guarantee that this should work, but it's a very widely supported
206  *  practice for low level manipulation.
207  *
208  *  IEEE double format summary:
209  *
210  *    seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
211  *       A        B        C        D        E        F        G        H
212  *
213  *    s       sign bit
214  *    eee...  exponent field
215  *    fff...  fraction
216  *
217  *  See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
218  *
219  *  NaNs are represented as exponent 0x7ff and mantissa != 0.  The NaN is a
220  *  signaling NaN when the highest bit of the mantissa is zero, and a quiet
221  *  NaN when the highest bit is set.
222  *
223  *  At least three memory layouts are relevant here:
224  *
225  *    A B C D E F G H    Big endian (e.g. 68k)           DUK_USE_DOUBLE_BE
226  *    H G F E D C B A    Little endian (e.g. x86)        DUK_USE_DOUBLE_LE
227  *    D C B A H G F E    Mixed/cross endian (e.g. ARM)   DUK_USE_DOUBLE_ME
228  *
229  *  ARM is a special case: ARM double values are in mixed/cross endian
230  *  format while ARM duk_uint64_t values are in standard little endian
231  *  format (H G F E D C B A).  When a double is read as a duk_uint64_t
232  *  from memory, the register will contain the (logical) value
233  *  E F G H A B C D.  This requires some special handling below.
234  *
235  *  Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
236  *  the logical (big endian) order:
237  *
238  *  byte order      duk_uint8_t    duk_uint16_t     duk_uint32_t
239  *    BE             01234567         0123               01
240  *    LE             76543210         3210               10
241  *    ME (ARM)       32107654         1032               01
242  *
243  *  Some processors may alter NaN values in a floating point load+store.
244  *  For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
245  *  quiet one.  This is catastrophic when NaN space is used in packed
246  *  duk_tval values.  See: misc/clang_aliasing.c.
247  */
248
249 #if !defined(DUK_DBLUNION_H_INCLUDED)
250 #define DUK_DBLUNION_H_INCLUDED
251
252 /*
253  *  Union for accessing double parts, also serves as packed duk_tval
254  */
255
256 union duk_double_union {
257         double d;
258         float f[2];
259 #if defined(DUK_USE_64BIT_OPS)
260         duk_uint64_t ull[1];
261 #endif
262         duk_uint32_t ui[2];
263         duk_uint16_t us[4];
264         duk_uint8_t uc[8];
265 #if defined(DUK_USE_PACKED_TVAL)
266         void *vp[2];  /* used by packed duk_tval, assumes sizeof(void *) == 4 */
267 #endif
268 };
269
270 typedef union duk_double_union duk_double_union;
271
272 /*
273  *  Indexes of various types with respect to big endian (logical) layout
274  */
275
276 #if defined(DUK_USE_DOUBLE_LE)
277 #if defined(DUK_USE_64BIT_OPS)
278 #define DUK_DBL_IDX_ULL0   0
279 #endif
280 #define DUK_DBL_IDX_UI0    1
281 #define DUK_DBL_IDX_UI1    0
282 #define DUK_DBL_IDX_US0    3
283 #define DUK_DBL_IDX_US1    2
284 #define DUK_DBL_IDX_US2    1
285 #define DUK_DBL_IDX_US3    0
286 #define DUK_DBL_IDX_UC0    7
287 #define DUK_DBL_IDX_UC1    6
288 #define DUK_DBL_IDX_UC2    5
289 #define DUK_DBL_IDX_UC3    4
290 #define DUK_DBL_IDX_UC4    3
291 #define DUK_DBL_IDX_UC5    2
292 #define DUK_DBL_IDX_UC6    1
293 #define DUK_DBL_IDX_UC7    0
294 #define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
295 #define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
296 #elif defined(DUK_USE_DOUBLE_BE)
297 #if defined(DUK_USE_64BIT_OPS)
298 #define DUK_DBL_IDX_ULL0   0
299 #endif
300 #define DUK_DBL_IDX_UI0    0
301 #define DUK_DBL_IDX_UI1    1
302 #define DUK_DBL_IDX_US0    0
303 #define DUK_DBL_IDX_US1    1
304 #define DUK_DBL_IDX_US2    2
305 #define DUK_DBL_IDX_US3    3
306 #define DUK_DBL_IDX_UC0    0
307 #define DUK_DBL_IDX_UC1    1
308 #define DUK_DBL_IDX_UC2    2
309 #define DUK_DBL_IDX_UC3    3
310 #define DUK_DBL_IDX_UC4    4
311 #define DUK_DBL_IDX_UC5    5
312 #define DUK_DBL_IDX_UC6    6
313 #define DUK_DBL_IDX_UC7    7
314 #define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
315 #define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
316 #elif defined(DUK_USE_DOUBLE_ME)
317 #if defined(DUK_USE_64BIT_OPS)
318 #define DUK_DBL_IDX_ULL0   0  /* not directly applicable, byte order differs from a double */
319 #endif
320 #define DUK_DBL_IDX_UI0    0
321 #define DUK_DBL_IDX_UI1    1
322 #define DUK_DBL_IDX_US0    1
323 #define DUK_DBL_IDX_US1    0
324 #define DUK_DBL_IDX_US2    3
325 #define DUK_DBL_IDX_US3    2
326 #define DUK_DBL_IDX_UC0    3
327 #define DUK_DBL_IDX_UC1    2
328 #define DUK_DBL_IDX_UC2    1
329 #define DUK_DBL_IDX_UC3    0
330 #define DUK_DBL_IDX_UC4    7
331 #define DUK_DBL_IDX_UC5    6
332 #define DUK_DBL_IDX_UC6    5
333 #define DUK_DBL_IDX_UC7    4
334 #define DUK_DBL_IDX_VP0    DUK_DBL_IDX_UI0  /* packed tval */
335 #define DUK_DBL_IDX_VP1    DUK_DBL_IDX_UI1  /* packed tval */
336 #else
337 #error internal error
338 #endif
339
340 /*
341  *  Helper macros for reading/writing memory representation parts, used
342  *  by duk_numconv.c and duk_tval.h.
343  */
344
345 #define DUK_DBLUNION_SET_DOUBLE(u,v)  do {  \
346                 (u)->d = (v); \
347         } while (0)
348
349 #define DUK_DBLUNION_SET_HIGH32(u,v)  do {  \
350                 (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
351         } while (0)
352
353 #if defined(DUK_USE_64BIT_OPS)
354 #if defined(DUK_USE_DOUBLE_ME)
355 #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
356                 (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
357         } while (0)
358 #else
359 #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
360                 (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
361         } while (0)
362 #endif
363 #else  /* DUK_USE_64BIT_OPS */
364 #define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v)  do { \
365                 (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
366                 (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
367         } while (0)
368 #endif  /* DUK_USE_64BIT_OPS */
369
370 #define DUK_DBLUNION_SET_LOW32(u,v)  do {  \
371                 (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
372         } while (0)
373
374 #define DUK_DBLUNION_GET_DOUBLE(u)  ((u)->d)
375 #define DUK_DBLUNION_GET_HIGH32(u)  ((u)->ui[DUK_DBL_IDX_UI0])
376 #define DUK_DBLUNION_GET_LOW32(u)   ((u)->ui[DUK_DBL_IDX_UI1])
377
378 #if defined(DUK_USE_64BIT_OPS)
379 #if defined(DUK_USE_DOUBLE_ME)
380 #define DUK_DBLUNION_SET_UINT64(u,v)  do { \
381                 (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \
382                 (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
383         } while (0)
384 #define DUK_DBLUNION_GET_UINT64(u) \
385         ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \
386          ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1]))
387 #else
388 #define DUK_DBLUNION_SET_UINT64(u,v)  do { \
389                 (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
390         } while (0)
391 #define DUK_DBLUNION_GET_UINT64(u)  ((u)->ull[DUK_DBL_IDX_ULL0])
392 #endif
393 #define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v))
394 #define DUK_DBLUNION_GET_INT64(u)   ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u)))
395 #endif  /* DUK_USE_64BIT_OPS */
396
397 /*
398  *  Double NaN manipulation macros related to NaN normalization needed when
399  *  using the packed duk_tval representation.  NaN normalization is necessary
400  *  to keep double values compatible with the duk_tval format.
401  *
402  *  When packed duk_tval is used, the NaN space is used to store pointers
403  *  and other tagged values in addition to NaNs.  Actual NaNs are normalized
404  *  to a specific quiet NaN.  The macros below are used by the implementation
405  *  to check and normalize NaN values when they might be created.  The macros
406  *  are essentially NOPs when the non-packed duk_tval representation is used.
407  *
408  *  A FULL check is exact and checks all bits.  A NOTFULL check is used by
409  *  the packed duk_tval and works correctly for all NaNs except those that
410  *  begin with 0x7ff0.  Since the 'normalized NaN' values used with packed
411  *  duk_tval begin with 0x7ff8, the partial check is reliable when packed
412  *  duk_tval is used.  The 0x7ff8 prefix means the normalized NaN will be a
413  *  quiet NaN regardless of its remaining lower bits.
414  *
415  *  The ME variant below is specifically for ARM byte order, which has the
416  *  feature that while doubles have a mixed byte order (32107654), unsigned
417  *  long long values has a little endian byte order (76543210).  When writing
418  *  a logical double value through a ULL pointer, the 32-bit words need to be
419  *  swapped; hence the #if defined()s below for ULL writes with DUK_USE_DOUBLE_ME.
420  *  This is not full ARM support but suffices for some environments.
421  */
422
423 #if defined(DUK_USE_64BIT_OPS)
424 #if defined(DUK_USE_DOUBLE_ME)
425 /* Macros for 64-bit ops + mixed endian doubles. */
426 #define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
427                 (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x000000007ff80000); \
428         } while (0)
429 #define DUK__DBLUNION_IS_NAN_FULL(u) \
430         ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000)) && \
431          ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0xffffffff000fffff)) != 0))
432 #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
433         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff80000))
434 #define DUK__DBLUNION_IS_ANYINF(u) \
435         (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x000000007ff00000))
436 #define DUK__DBLUNION_IS_POSINF(u) \
437         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x000000007ff00000))
438 #define DUK__DBLUNION_IS_NEGINF(u) \
439         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x00000000fff00000))
440 #define DUK__DBLUNION_IS_ANYZERO(u) \
441         (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0xffffffff7fffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
442 #define DUK__DBLUNION_IS_POSZERO(u) \
443         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
444 #define DUK__DBLUNION_IS_NEGZERO(u) \
445         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000080000000))
446 #else
447 /* Macros for 64-bit ops + big/little endian doubles. */
448 #define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
449                 (u)->ull[DUK_DBL_IDX_ULL0] = DUK_U64_CONSTANT(0x7ff8000000000000); \
450         } while (0)
451 #define DUK__DBLUNION_IS_NAN_FULL(u) \
452         ((((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000)) && \
453          ((((u)->ull[DUK_DBL_IDX_ULL0]) & DUK_U64_CONSTANT(0x000fffffffffffff)) != 0))
454 #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
455         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff8000000000000))
456 #define DUK__DBLUNION_IS_ANYINF(u) \
457         (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x7ff0000000000000))
458 #define DUK__DBLUNION_IS_POSINF(u) \
459         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x7ff0000000000000))
460 #define DUK__DBLUNION_IS_NEGINF(u) \
461         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0xfff0000000000000))
462 #define DUK__DBLUNION_IS_ANYZERO(u) \
463         (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7fffffffffffffff)) == DUK_U64_CONSTANT(0x0000000000000000))
464 #define DUK__DBLUNION_IS_POSZERO(u) \
465         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x0000000000000000))
466 #define DUK__DBLUNION_IS_NEGZERO(u) \
467         ((u)->ull[DUK_DBL_IDX_ULL0] == DUK_U64_CONSTANT(0x8000000000000000))
468 #endif
469 #else  /* DUK_USE_64BIT_OPS */
470 /* Macros for no 64-bit ops, any endianness. */
471 #define DUK__DBLUNION_SET_NAN_FULL(u)  do { \
472                 (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
473                 (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
474         } while (0)
475 #define DUK__DBLUNION_IS_NAN_FULL(u) \
476         ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
477          (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
478           (u)->ui[DUK_DBL_IDX_UI1] != 0))
479 #define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
480         (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
481          ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
482 #define DUK__DBLUNION_IS_ANYINF(u) \
483         ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x7ff00000UL) && \
484          ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
485 #define DUK__DBLUNION_IS_POSINF(u) \
486         (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff00000UL) && \
487          ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
488 #define DUK__DBLUNION_IS_NEGINF(u) \
489         (((u)->ui[DUK_DBL_IDX_UI0] == 0xfff00000UL) && \
490          ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
491 #define DUK__DBLUNION_IS_ANYZERO(u) \
492         ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7fffffffUL) == 0x00000000UL) && \
493          ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
494 #define DUK__DBLUNION_IS_POSZERO(u) \
495         (((u)->ui[DUK_DBL_IDX_UI0] == 0x00000000UL) && \
496          ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
497 #define DUK__DBLUNION_IS_NEGZERO(u) \
498         (((u)->ui[DUK_DBL_IDX_UI0] == 0x80000000UL) && \
499          ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
500 #endif  /* DUK_USE_64BIT_OPS */
501
502 #define DUK__DBLUNION_SET_NAN_NOTFULL(u)  do { \
503                 (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
504         } while (0)
505
506 #define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
507         /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
508         ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
509          (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
510
511 #define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
512         /* E == 0x7ff, F == 8 => normalized NaN */ \
513         ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
514
515 #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u)  do { \
516                 if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
517                         DUK__DBLUNION_SET_NAN_FULL((u)); \
518                 } \
519         } while (0)
520
521 #define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u)  do { \
522                 if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \
523                         DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
524                 } \
525         } while (0)
526
527 /* Concrete macros for NaN handling used by the implementation internals.
528  * Chosen so that they match the duk_tval representation: with a packed
529  * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
530  * these are essentially NOPs.
531  */
532
533 #if defined(DUK_USE_PACKED_TVAL)
534 #if defined(DUK_USE_FULL_TVAL)
535 #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
536 #define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_FULL((u))
537 #define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
538 #define DUK_DBLUNION_SET_NAN(d)              DUK__DBLUNION_SET_NAN_FULL((d))
539 #else
540 #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
541 #define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_NOTFULL((u))
542 #define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
543 #define DUK_DBLUNION_SET_NAN(d)              DUK__DBLUNION_SET_NAN_NOTFULL((d))
544 #endif
545 #define DUK_DBLUNION_IS_NORMALIZED(u) \
546         (!DUK_DBLUNION_IS_NAN((u)) ||  /* either not a NaN */ \
547          DUK_DBLUNION_IS_NORMALIZED_NAN((u)))  /* or is a normalized NaN */
548 #else  /* DUK_USE_PACKED_TVAL */
549 #define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u)  /* nop: no need to normalize */
550 #define DUK_DBLUNION_IS_NAN(u)               DUK__DBLUNION_IS_NAN_FULL((u))  /* (DUK_ISNAN((u)->d)) */
551 #define DUK_DBLUNION_IS_NORMALIZED_NAN(u)    DUK__DBLUNION_IS_NAN_FULL((u))  /* (DUK_ISNAN((u)->d)) */
552 #define DUK_DBLUNION_IS_NORMALIZED(u)        1  /* all doubles are considered normalized */
553 #define DUK_DBLUNION_SET_NAN(u)  do { \
554                 /* in non-packed representation we don't care about which NaN is used */ \
555                 (u)->d = DUK_DOUBLE_NAN; \
556         } while (0)
557 #endif  /* DUK_USE_PACKED_TVAL */
558
559 #define DUK_DBLUNION_IS_ANYINF(u) DUK__DBLUNION_IS_ANYINF((u))
560 #define DUK_DBLUNION_IS_POSINF(u) DUK__DBLUNION_IS_POSINF((u))
561 #define DUK_DBLUNION_IS_NEGINF(u) DUK__DBLUNION_IS_NEGINF((u))
562
563 #define DUK_DBLUNION_IS_ANYZERO(u) DUK__DBLUNION_IS_ANYZERO((u))
564 #define DUK_DBLUNION_IS_POSZERO(u) DUK__DBLUNION_IS_POSZERO((u))
565 #define DUK_DBLUNION_IS_NEGZERO(u) DUK__DBLUNION_IS_NEGZERO((u))
566
567 /* XXX: native 64-bit byteswaps when available */
568
569 /* 64-bit byteswap, same operation independent of target endianness. */
570 #define DUK_DBLUNION_BSWAP64(u) do { \
571                 duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
572                 duk__bswaptmp1 = (u)->ui[0]; \
573                 duk__bswaptmp2 = (u)->ui[1]; \
574                 duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
575                 duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
576                 (u)->ui[0] = duk__bswaptmp2; \
577                 (u)->ui[1] = duk__bswaptmp1; \
578         } while (0)
579
580 /* Byteswap an IEEE double in the duk_double_union from host to network
581  * order.  For a big endian target this is a no-op.
582  */
583 #if defined(DUK_USE_DOUBLE_LE)
584 #define DUK_DBLUNION_DOUBLE_HTON(u) do { \
585                 duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
586                 duk__bswaptmp1 = (u)->ui[0]; \
587                 duk__bswaptmp2 = (u)->ui[1]; \
588                 duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
589                 duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
590                 (u)->ui[0] = duk__bswaptmp2; \
591                 (u)->ui[1] = duk__bswaptmp1; \
592         } while (0)
593 #elif defined(DUK_USE_DOUBLE_ME)
594 #define DUK_DBLUNION_DOUBLE_HTON(u) do { \
595                 duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
596                 duk__bswaptmp1 = (u)->ui[0]; \
597                 duk__bswaptmp2 = (u)->ui[1]; \
598                 duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
599                 duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
600                 (u)->ui[0] = duk__bswaptmp1; \
601                 (u)->ui[1] = duk__bswaptmp2; \
602         } while (0)
603 #elif defined(DUK_USE_DOUBLE_BE)
604 #define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0)
605 #else
606 #error internal error, double endianness insane
607 #endif
608
609 /* Reverse operation is the same. */
610 #define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u))
611
612 /* Some sign bit helpers. */
613 #if defined(DUK_USE_64BIT_OPS)
614 #define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000)) != 0)
615 #define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ull[DUK_DBL_IDX_ULL0] >> 63U))
616 #else
617 #define DUK_DBLUNION_HAS_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] & 0x80000000UL) != 0)
618 #define DUK_DBLUNION_GET_SIGNBIT(u) (((u)->ui[DUK_DBL_IDX_UI0] >> 31U))
619 #endif
620
621 #endif  /* DUK_DBLUNION_H_INCLUDED */
622 /* #include duk_replacements.h */
623 #line 1 "duk_replacements.h"
624 #if !defined(DUK_REPLACEMENTS_H_INCLUDED)
625 #define DUK_REPLACEMENTS_H_INCLUDED
626
627 #if !defined(DUK_SINGLE_FILE)
628 #if defined(DUK_USE_COMPUTED_INFINITY)
629 DUK_INTERNAL_DECL double duk_computed_infinity;
630 #endif
631 #if defined(DUK_USE_COMPUTED_NAN)
632 DUK_INTERNAL_DECL double duk_computed_nan;
633 #endif
634 #endif  /* !DUK_SINGLE_FILE */
635
636 #if defined(DUK_USE_REPL_FPCLASSIFY)
637 DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
638 #endif
639 #if defined(DUK_USE_REPL_SIGNBIT)
640 DUK_INTERNAL_DECL int duk_repl_signbit(double x);
641 #endif
642 #if defined(DUK_USE_REPL_ISFINITE)
643 DUK_INTERNAL_DECL int duk_repl_isfinite(double x);
644 #endif
645 #if defined(DUK_USE_REPL_ISNAN)
646 DUK_INTERNAL_DECL int duk_repl_isnan(double x);
647 #endif
648 #if defined(DUK_USE_REPL_ISINF)
649 DUK_INTERNAL_DECL int duk_repl_isinf(double x);
650 #endif
651
652 #endif  /* DUK_REPLACEMENTS_H_INCLUDED */
653 /* #include duk_jmpbuf.h */
654 #line 1 "duk_jmpbuf.h"
655 /*
656  *  Wrapper for jmp_buf.
657  *
658  *  This is used because jmp_buf is an array type for backward compatibility.
659  *  Wrapping jmp_buf in a struct makes pointer references, sizeof, etc,
660  *  behave more intuitively.
661  *
662  *  http://en.wikipedia.org/wiki/Setjmp.h#Member_types
663  */
664
665 #if !defined(DUK_JMPBUF_H_INCLUDED)
666 #define DUK_JMPBUF_H_INCLUDED
667
668 #if defined(DUK_USE_CPP_EXCEPTIONS)
669 struct duk_jmpbuf {
670         duk_small_int_t dummy;  /* unused */
671 };
672 #else
673 struct duk_jmpbuf {
674         DUK_JMPBUF_TYPE jb;
675 };
676 #endif
677
678 #endif  /* DUK_JMPBUF_H_INCLUDED */
679 /* #include duk_exception.h */
680 #line 1 "duk_exception.h"
681 /*
682  *  Exceptions for Duktape internal throws when C++ exceptions are used
683  *  for long control transfers.
684  */
685
686 #if !defined(DUK_EXCEPTION_H_INCLUDED)
687 #define DUK_EXCEPTION_H_INCLUDED
688
689 #if defined(DUK_USE_CPP_EXCEPTIONS)
690 /* Internal exception used as a setjmp-longjmp replacement.  User code should
691  * NEVER see or catch this exception, so it doesn't inherit from any base
692  * class which should minimize the chance of user code accidentally catching
693  * the exception.
694  */
695 class duk_internal_exception {
696         /* intentionally empty */
697 };
698
699 /* Fatal error, thrown as a specific C++ exception with C++ exceptions
700  * enabled.  It is unsafe to continue; doing so may cause crashes or memory
701  * leaks.  This is intended to be either uncaught, or caught by user code
702  * aware of the "unsafe to continue" semantics.
703  */
704 class duk_fatal_exception : public virtual std::runtime_error {
705  public:
706         duk_fatal_exception(const char *message) : std::runtime_error(message) {}
707 };
708 #endif
709
710 #endif  /* DUK_EXCEPTION_H_INCLUDED */
711 /* #include duk_forwdecl.h */
712 #line 1 "duk_forwdecl.h"
713 /*
714  *  Forward declarations for all Duktape structures.
715  */
716
717 #if !defined(DUK_FORWDECL_H_INCLUDED)
718 #define DUK_FORWDECL_H_INCLUDED
719
720 /*
721  *  Forward declarations
722  */
723
724 #if defined(DUK_USE_CPP_EXCEPTIONS)
725 class duk_internal_exception;
726 #else
727 struct duk_jmpbuf;
728 #endif
729
730 /* duk_tval intentionally skipped */
731 struct duk_heaphdr;
732 struct duk_heaphdr_string;
733 struct duk_harray;
734 struct duk_hstring;
735 struct duk_hstring_external;
736 struct duk_hobject;
737 struct duk_hcompfunc;
738 struct duk_hnatfunc;
739 struct duk_hboundfunc;
740 struct duk_hthread;
741 struct duk_hbufobj;
742 struct duk_hdecenv;
743 struct duk_hobjenv;
744 struct duk_hproxy;
745 struct duk_hbuffer;
746 struct duk_hbuffer_fixed;
747 struct duk_hbuffer_dynamic;
748 struct duk_hbuffer_external;
749
750 struct duk_propaccessor;
751 union duk_propvalue;
752 struct duk_propdesc;
753
754 struct duk_heap;
755 struct duk_breakpoint;
756
757 struct duk_activation;
758 struct duk_catcher;
759 struct duk_ljstate;
760 struct duk_strcache_entry;
761 struct duk_litcache_entry;
762 struct duk_strtab_entry;
763
764 #if defined(DUK_USE_DEBUG)
765 struct duk_fixedbuffer;
766 #endif
767
768 struct duk_bitdecoder_ctx;
769 struct duk_bitencoder_ctx;
770 struct duk_bufwriter_ctx;
771
772 struct duk_token;
773 struct duk_re_token;
774 struct duk_lexer_point;
775 struct duk_lexer_ctx;
776 struct duk_lexer_codepoint;
777
778 struct duk_compiler_instr;
779 struct duk_compiler_func;
780 struct duk_compiler_ctx;
781
782 struct duk_re_matcher_ctx;
783 struct duk_re_compiler_ctx;
784
785 #if defined(DUK_USE_CPP_EXCEPTIONS)
786 /* no typedef */
787 #else
788 typedef struct duk_jmpbuf duk_jmpbuf;
789 #endif
790
791 /* duk_tval intentionally skipped */
792 typedef struct duk_heaphdr duk_heaphdr;
793 typedef struct duk_heaphdr_string duk_heaphdr_string;
794 typedef struct duk_harray duk_harray;
795 typedef struct duk_hstring duk_hstring;
796 typedef struct duk_hstring_external duk_hstring_external;
797 typedef struct duk_hobject duk_hobject;
798 typedef struct duk_hcompfunc duk_hcompfunc;
799 typedef struct duk_hnatfunc duk_hnatfunc;
800 typedef struct duk_hboundfunc duk_hboundfunc;
801 typedef struct duk_hthread duk_hthread;
802 typedef struct duk_hbufobj duk_hbufobj;
803 typedef struct duk_hdecenv duk_hdecenv;
804 typedef struct duk_hobjenv duk_hobjenv;
805 typedef struct duk_hproxy duk_hproxy;
806 typedef struct duk_hbuffer duk_hbuffer;
807 typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
808 typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
809 typedef struct duk_hbuffer_external duk_hbuffer_external;
810
811 typedef struct duk_propaccessor duk_propaccessor;
812 typedef union duk_propvalue duk_propvalue;
813 typedef struct duk_propdesc duk_propdesc;
814
815 typedef struct duk_heap duk_heap;
816 typedef struct duk_breakpoint duk_breakpoint;
817
818 typedef struct duk_activation duk_activation;
819 typedef struct duk_catcher duk_catcher;
820 typedef struct duk_ljstate duk_ljstate;
821 typedef struct duk_strcache_entry duk_strcache_entry;
822 typedef struct duk_litcache_entry duk_litcache_entry;
823 typedef struct duk_strtab_entry duk_strtab_entry;
824
825 #if defined(DUK_USE_DEBUG)
826 typedef struct duk_fixedbuffer duk_fixedbuffer;
827 #endif
828
829 typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx;
830 typedef struct duk_bitencoder_ctx duk_bitencoder_ctx;
831 typedef struct duk_bufwriter_ctx duk_bufwriter_ctx;
832
833 typedef struct duk_token duk_token;
834 typedef struct duk_re_token duk_re_token;
835 typedef struct duk_lexer_point duk_lexer_point;
836 typedef struct duk_lexer_ctx duk_lexer_ctx;
837 typedef struct duk_lexer_codepoint duk_lexer_codepoint;
838
839 typedef struct duk_compiler_instr duk_compiler_instr;
840 typedef struct duk_compiler_func duk_compiler_func;
841 typedef struct duk_compiler_ctx duk_compiler_ctx;
842
843 typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
844 typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
845
846 #endif  /* DUK_FORWDECL_H_INCLUDED */
847 /* #include duk_tval.h */
848 #line 1 "duk_tval.h"
849 /*
850  *  Tagged type definition (duk_tval) and accessor macros.
851  *
852  *  Access all fields through the accessor macros, as the representation
853  *  is quite tricky.
854  *
855  *  There are two packed type alternatives: an 8-byte representation
856  *  based on an IEEE double (preferred for compactness), and a 12-byte
857  *  representation (portability).  The latter is needed also in e.g.
858  *  64-bit environments (it usually pads to 16 bytes per value).
859  *
860  *  Selecting the tagged type format involves many trade-offs (memory
861  *  use, size and performance of generated code, portability, etc).
862  *
863  *  NB: because macro arguments are often expressions, macros should
864  *  avoid evaluating their argument more than once.
865  */
866
867 #if !defined(DUK_TVAL_H_INCLUDED)
868 #define DUK_TVAL_H_INCLUDED
869
870 /* sanity */
871 #if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE)
872 #error unsupported: cannot determine byte order variant
873 #endif
874
875 #if defined(DUK_USE_PACKED_TVAL)
876 /* ======================================================================== */
877
878 /*
879  *  Packed 8-byte representation
880  */
881
882 /* use duk_double_union as duk_tval directly */
883 typedef union duk_double_union duk_tval;
884 typedef struct {
885         duk_uint16_t a;
886         duk_uint16_t b;
887         duk_uint16_t c;
888         duk_uint16_t d;
889 } duk_tval_unused;
890
891 /* tags */
892 #define DUK_TAG_NORMALIZED_NAN    0x7ff8UL   /* the NaN variant we use */
893 /* avoid tag 0xfff0, no risk of confusion with negative infinity */
894 #define DUK_TAG_MIN               0xfff1UL
895 #if defined(DUK_USE_FASTINT)
896 #define DUK_TAG_FASTINT           0xfff1UL   /* embed: integer value */
897 #endif
898 #define DUK_TAG_UNUSED            0xfff2UL   /* marker; not actual tagged value */
899 #define DUK_TAG_UNDEFINED         0xfff3UL   /* embed: nothing */
900 #define DUK_TAG_NULL              0xfff4UL   /* embed: nothing */
901 #define DUK_TAG_BOOLEAN           0xfff5UL   /* embed: 0 or 1 (false or true) */
902 /* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */
903 #define DUK_TAG_POINTER           0xfff6UL   /* embed: void ptr */
904 #define DUK_TAG_LIGHTFUNC         0xfff7UL   /* embed: func ptr */
905 #define DUK_TAG_STRING            0xfff8UL   /* embed: duk_hstring ptr */
906 #define DUK_TAG_OBJECT            0xfff9UL   /* embed: duk_hobject ptr */
907 #define DUK_TAG_BUFFER            0xfffaUL   /* embed: duk_hbuffer ptr */
908 #define DUK_TAG_MAX               0xfffaUL
909
910 /* for convenience */
911 #define DUK_XTAG_BOOLEAN_FALSE    0xfff50000UL
912 #define DUK_XTAG_BOOLEAN_TRUE     0xfff50001UL
913
914 #define DUK_TVAL_IS_VALID_TAG(tv) \
915         (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
916
917 /* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */
918 #define DUK_TVAL_UNUSED_INITIALIZER() \
919         { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED }
920
921 /* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
922 #if defined(DUK_USE_64BIT_OPS)
923 #if defined(DUK_USE_DOUBLE_ME)
924 #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag)  do { \
925                 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
926         } while (0)
927 #else
928 #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag)  do { \
929                 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
930         } while (0)
931 #endif
932 #else  /* DUK_USE_64BIT_OPS */
933 #define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag)  do { \
934                 duk_tval *duk__tv; \
935                 duk__tv = (tv); \
936                 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
937                 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
938         } while (0)
939 #endif  /* DUK_USE_64BIT_OPS */
940
941 #if defined(DUK_USE_64BIT_OPS)
942 /* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
943 #if defined(DUK_USE_DOUBLE_ME)
944 #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags)  do { \
945                 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
946                                               ((duk_uint64_t) (flags)) | \
947                                               (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
948         } while (0)
949 #else
950 #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags)  do { \
951                 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
952                                               (((duk_uint64_t) (flags)) << 32) | \
953                                               ((duk_uint64_t) (duk_uint32_t) (fp)); \
954         } while (0)
955 #endif
956 #else  /* DUK_USE_64BIT_OPS */
957 #define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags)  do { \
958                 duk_tval *duk__tv; \
959                 duk__tv = (tv); \
960                 duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
961                 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
962         } while (0)
963 #endif  /* DUK_USE_64BIT_OPS */
964
965 #if defined(DUK_USE_FASTINT)
966 /* Note: masking is done for 'i' to deal with negative numbers correctly */
967 #if defined(DUK_USE_DOUBLE_ME)
968 #define DUK__TVAL_SET_I48(tv,i)  do { \
969                 duk_tval *duk__tv; \
970                 duk__tv = (tv); \
971                 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
972                 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
973         } while (0)
974 #define DUK__TVAL_SET_U32(tv,i)  do { \
975                 duk_tval *duk__tv; \
976                 duk__tv = (tv); \
977                 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
978                 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
979         } while (0)
980 #else
981 #define DUK__TVAL_SET_I48(tv,i)  do { \
982                 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & DUK_U64_CONSTANT(0x0000ffffffffffff)); \
983         } while (0)
984 #define DUK__TVAL_SET_U32(tv,i)  do { \
985                 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
986         } while (0)
987 #endif
988
989 /* This needs to go through a cast because sign extension is needed. */
990 #define DUK__TVAL_SET_I32(tv,i)  do { \
991                 duk_int64_t duk__tmp = (duk_int64_t) (i); \
992                 DUK_TVAL_SET_I48((tv), duk__tmp); \
993         } while (0)
994
995 /* XXX: Clumsy sign extend and masking of 16 topmost bits. */
996 #if defined(DUK_USE_DOUBLE_ME)
997 #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)
998 #else
999 #define DUK__TVAL_GET_FASTINT(tv)      ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
1000 #endif
1001 #define DUK__TVAL_GET_FASTINT_U32(tv)  ((tv)->ui[DUK_DBL_IDX_UI1])
1002 #define DUK__TVAL_GET_FASTINT_I32(tv)  ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1])
1003 #endif  /* DUK_USE_FASTINT */
1004
1005 #define DUK_TVAL_SET_UNDEFINED(tv)  do { \
1006                 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
1007         } while (0)
1008 #define DUK_TVAL_SET_UNUSED(tv)  do { \
1009                 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
1010         } while (0)
1011 #define DUK_TVAL_SET_NULL(tv)  do { \
1012                 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
1013         } while (0)
1014
1015 #define DUK_TVAL_SET_BOOLEAN(tv,val)         DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
1016
1017 #define DUK_TVAL_SET_NAN(tv)                 DUK_DBLUNION_SET_NAN_FULL((tv))
1018
1019 /* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
1020 #if defined(DUK_USE_FASTINT)
1021 #define DUK_TVAL_SET_DOUBLE(tv,d)  do { \
1022                 duk_double_t duk__dblval; \
1023                 duk__dblval = (d); \
1024                 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
1025                 DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
1026         } while (0)
1027 #define DUK_TVAL_SET_I48(tv,i)               DUK__TVAL_SET_I48((tv), (i))
1028 #define DUK_TVAL_SET_I32(tv,i)               DUK__TVAL_SET_I32((tv), (i))
1029 #define DUK_TVAL_SET_U32(tv,i)               DUK__TVAL_SET_U32((tv), (i))
1030 #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d)  duk_tval_set_number_chkfast_fast((tv), (d))
1031 #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d)  duk_tval_set_number_chkfast_slow((tv), (d))
1032 #define DUK_TVAL_SET_NUMBER(tv,d)            DUK_TVAL_SET_DOUBLE((tv), (d))
1033 #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv)  do { \
1034                 duk_tval *duk__tv; \
1035                 duk_double_t duk__d; \
1036                 duk__tv = (tv); \
1037                 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
1038                         duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
1039                         DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
1040                 } \
1041         } while (0)
1042 #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv)  do { \
1043                 duk_tval *duk__tv; \
1044                 duk_double_t duk__d; \
1045                 duk__tv = (tv); \
1046                 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
1047                         duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
1048                         DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
1049                 } \
1050         } while (0)
1051 #else  /* DUK_USE_FASTINT */
1052 #define DUK_TVAL_SET_DOUBLE(tv,d)  do { \
1053                 duk_double_t duk__dblval; \
1054                 duk__dblval = (d); \
1055                 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
1056                 DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
1057         } while (0)
1058 #define DUK_TVAL_SET_I48(tv,i)               DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))  /* XXX: fast int-to-double */
1059 #define DUK_TVAL_SET_I32(tv,i)               DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
1060 #define DUK_TVAL_SET_U32(tv,i)               DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
1061 #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d)    DUK_TVAL_SET_DOUBLE((tv), (d))
1062 #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d)    DUK_TVAL_SET_DOUBLE((tv), (d))
1063 #define DUK_TVAL_SET_NUMBER(tv,d)            DUK_TVAL_SET_DOUBLE((tv), (d))
1064 #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv)  do { } while (0)
1065 #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv)  do { } while (0)
1066 #endif  /* DUK_USE_FASTINT */
1067
1068 #define DUK_TVAL_SET_FASTINT(tv,i)           DUK_TVAL_SET_I48((tv), (i))  /* alias */
1069
1070 #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags)  DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags))
1071 #define DUK_TVAL_SET_STRING(tv,h)            DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING)
1072 #define DUK_TVAL_SET_OBJECT(tv,h)            DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT)
1073 #define DUK_TVAL_SET_BUFFER(tv,h)            DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER)
1074 #define DUK_TVAL_SET_POINTER(tv,p)           DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER)
1075
1076 #define DUK_TVAL_SET_TVAL(tv,x)              do { *(tv) = *(x); } while (0)
1077
1078 /* getters */
1079 #define DUK_TVAL_GET_BOOLEAN(tv)             ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US1])
1080 #if defined(DUK_USE_FASTINT)
1081 #define DUK_TVAL_GET_DOUBLE(tv)              ((tv)->d)
1082 #define DUK_TVAL_GET_FASTINT(tv)             DUK__TVAL_GET_FASTINT((tv))
1083 #define DUK_TVAL_GET_FASTINT_U32(tv)         DUK__TVAL_GET_FASTINT_U32((tv))
1084 #define DUK_TVAL_GET_FASTINT_I32(tv)         DUK__TVAL_GET_FASTINT_I32((tv))
1085 #define DUK_TVAL_GET_NUMBER(tv)              duk_tval_get_number_packed((tv))
1086 #else
1087 #define DUK_TVAL_GET_NUMBER(tv)              ((tv)->d)
1088 #define DUK_TVAL_GET_DOUBLE(tv)              ((tv)->d)
1089 #endif
1090 #define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags)  do { \
1091                 (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
1092                 (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \
1093         } while (0)
1094 #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv)   ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1]))
1095 #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv)     (((duk_small_uint_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
1096 #define DUK_TVAL_GET_STRING(tv)              ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1])
1097 #define DUK_TVAL_GET_OBJECT(tv)              ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1])
1098 #define DUK_TVAL_GET_BUFFER(tv)              ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1])
1099 #define DUK_TVAL_GET_POINTER(tv)             ((void *) (tv)->vp[DUK_DBL_IDX_VP1])
1100 #define DUK_TVAL_GET_HEAPHDR(tv)             ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1])
1101
1102 /* decoding */
1103 #define DUK_TVAL_GET_TAG(tv)                 ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0])
1104
1105 #define DUK_TVAL_IS_UNDEFINED(tv)            (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED)
1106 #define DUK_TVAL_IS_UNUSED(tv)               (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED)
1107 #define DUK_TVAL_IS_NULL(tv)                 (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL)
1108 #define DUK_TVAL_IS_BOOLEAN(tv)              (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN)
1109 #define DUK_TVAL_IS_BOOLEAN_TRUE(tv)         ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
1110 #define DUK_TVAL_IS_BOOLEAN_FALSE(tv)        ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
1111 #define DUK_TVAL_IS_LIGHTFUNC(tv)            (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC)
1112 #define DUK_TVAL_IS_STRING(tv)               (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING)
1113 #define DUK_TVAL_IS_OBJECT(tv)               (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT)
1114 #define DUK_TVAL_IS_BUFFER(tv)               (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER)
1115 #define DUK_TVAL_IS_POINTER(tv)              (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER)
1116 #if defined(DUK_USE_FASTINT)
1117 /* 0xfff0 is -Infinity */
1118 #define DUK_TVAL_IS_DOUBLE(tv)               (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
1119 #define DUK_TVAL_IS_FASTINT(tv)              (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT)
1120 #define DUK_TVAL_IS_NUMBER(tv)               (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL)
1121 #else
1122 #define DUK_TVAL_IS_NUMBER(tv)               (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
1123 #define DUK_TVAL_IS_DOUBLE(tv)               DUK_TVAL_IS_NUMBER((tv))
1124 #endif
1125
1126 /* This is performance critical because it appears in every DECREF. */
1127 #define DUK_TVAL_IS_HEAP_ALLOCATED(tv)       (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING)
1128
1129 #if defined(DUK_USE_FASTINT)
1130 DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv);
1131 #endif
1132
1133 #else  /* DUK_USE_PACKED_TVAL */
1134 /* ======================================================================== */
1135
1136 /*
1137  *  Portable 12-byte representation
1138  */
1139
1140 /* Note: not initializing all bytes is normally not an issue: Duktape won't
1141  * read or use the uninitialized bytes so valgrind won't issue warnings.
1142  * In some special cases a harmless valgrind warning may be issued though.
1143  * For example, the DumpHeap debugger command writes out a compiled function's
1144  * 'data' area as is, including any uninitialized bytes, which causes a
1145  * valgrind warning.
1146  */
1147
1148 typedef struct duk_tval_struct duk_tval;
1149
1150 struct duk_tval_struct {
1151         duk_small_uint_t t;
1152         duk_small_uint_t v_extra;
1153         union {
1154                 duk_double_t d;
1155                 duk_small_int_t i;
1156 #if defined(DUK_USE_FASTINT)
1157                 duk_int64_t fi;  /* if present, forces 16-byte duk_tval */
1158 #endif
1159                 void *voidptr;
1160                 duk_hstring *hstring;
1161                 duk_hobject *hobject;
1162                 duk_hcompfunc *hcompfunc;
1163                 duk_hnatfunc *hnatfunc;
1164                 duk_hthread *hthread;
1165                 duk_hbuffer *hbuffer;
1166                 duk_heaphdr *heaphdr;
1167                 duk_c_function lightfunc;
1168         } v;
1169 };
1170
1171 typedef struct {
1172         duk_small_uint_t t;
1173         duk_small_uint_t v_extra;
1174         /* The rest of the fields don't matter except for debug dumps and such
1175          * for which a partial initializer may trigger out-ot-bounds memory
1176          * reads.  Include a double field which is usually as large or larger
1177          * than pointers (not always however).
1178          */
1179         duk_double_t d;
1180 } duk_tval_unused;
1181
1182 #define DUK_TVAL_UNUSED_INITIALIZER() \
1183         { DUK_TAG_UNUSED, 0, 0.0 }
1184
1185 #define DUK_TAG_MIN                   0
1186 #define DUK_TAG_NUMBER                0  /* DUK_TAG_NUMBER only defined for non-packed duk_tval */
1187 #if defined(DUK_USE_FASTINT)
1188 #define DUK_TAG_FASTINT               1
1189 #endif
1190 #define DUK_TAG_UNDEFINED             2
1191 #define DUK_TAG_NULL                  3
1192 #define DUK_TAG_BOOLEAN               4
1193 #define DUK_TAG_POINTER               5
1194 #define DUK_TAG_LIGHTFUNC             6
1195 #define DUK_TAG_UNUSED                7  /* marker; not actual tagged type */
1196 #define DUK_TAG_STRING                8  /* first heap allocated, match bit boundary */
1197 #define DUK_TAG_OBJECT                9
1198 #define DUK_TAG_BUFFER                10
1199 #define DUK_TAG_MAX                   10
1200
1201 #define DUK_TVAL_IS_VALID_TAG(tv) \
1202         (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
1203
1204 /* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code
1205  * to support the 8-byte representation.  Further, it is a non-heap-allocated
1206  * type so it should come before DUK_TAG_STRING.  Finally, it should not break
1207  * the tag value ranges covered by case-clauses in a switch-case.
1208  */
1209
1210 /* setters */
1211 #define DUK_TVAL_SET_UNDEFINED(tv)  do { \
1212                 duk_tval *duk__tv; \
1213                 duk__tv = (tv); \
1214                 duk__tv->t = DUK_TAG_UNDEFINED; \
1215         } while (0)
1216
1217 #define DUK_TVAL_SET_UNUSED(tv)  do { \
1218                 duk_tval *duk__tv; \
1219                 duk__tv = (tv); \
1220                 duk__tv->t = DUK_TAG_UNUSED; \
1221         } while (0)
1222
1223 #define DUK_TVAL_SET_NULL(tv)  do { \
1224                 duk_tval *duk__tv; \
1225                 duk__tv = (tv); \
1226                 duk__tv->t = DUK_TAG_NULL; \
1227         } while (0)
1228
1229 #define DUK_TVAL_SET_BOOLEAN(tv,val)  do { \
1230                 duk_tval *duk__tv; \
1231                 duk__tv = (tv); \
1232                 duk__tv->t = DUK_TAG_BOOLEAN; \
1233                 duk__tv->v.i = (duk_small_int_t) (val); \
1234         } while (0)
1235
1236 #if defined(DUK_USE_FASTINT)
1237 #define DUK_TVAL_SET_DOUBLE(tv,val)  do { \
1238                 duk_tval *duk__tv; \
1239                 duk_double_t duk__dblval; \
1240                 duk__dblval = (val); \
1241                 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
1242                 duk__tv = (tv); \
1243                 duk__tv->t = DUK_TAG_NUMBER; \
1244                 duk__tv->v.d = duk__dblval; \
1245         } while (0)
1246 #define DUK_TVAL_SET_I48(tv,val)  do { \
1247                 duk_tval *duk__tv; \
1248                 duk__tv = (tv); \
1249                 duk__tv->t = DUK_TAG_FASTINT; \
1250                 duk__tv->v.fi = (val); \
1251         } while (0)
1252 #define DUK_TVAL_SET_U32(tv,val)  do { \
1253                 duk_tval *duk__tv; \
1254                 duk__tv = (tv); \
1255                 duk__tv->t = DUK_TAG_FASTINT; \
1256                 duk__tv->v.fi = (duk_int64_t) (val); \
1257         } while (0)
1258 #define DUK_TVAL_SET_I32(tv,val)  do { \
1259                 duk_tval *duk__tv; \
1260                 duk__tv = (tv); \
1261                 duk__tv->t = DUK_TAG_FASTINT; \
1262                 duk__tv->v.fi = (duk_int64_t) (val); \
1263         } while (0)
1264 #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
1265         duk_tval_set_number_chkfast_fast((tv), (d))
1266 #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
1267         duk_tval_set_number_chkfast_slow((tv), (d))
1268 #define DUK_TVAL_SET_NUMBER(tv,val) \
1269         DUK_TVAL_SET_DOUBLE((tv), (val))
1270 #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv)  do { \
1271                 duk_tval *duk__tv; \
1272                 duk_double_t duk__d; \
1273                 duk__tv = (tv); \
1274                 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
1275                         duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
1276                         DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
1277                 } \
1278         } while (0)
1279 #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv)  do { \
1280                 duk_tval *duk__tv; \
1281                 duk_double_t duk__d; \
1282                 duk__tv = (tv); \
1283                 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
1284                         duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
1285                         DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
1286                 } \
1287         } while (0)
1288 #else  /* DUK_USE_FASTINT */
1289 #define DUK_TVAL_SET_DOUBLE(tv,d) \
1290         DUK_TVAL_SET_NUMBER((tv), (d))
1291 #define DUK_TVAL_SET_I48(tv,val) \
1292         DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))  /* XXX: fast int-to-double */
1293 #define DUK_TVAL_SET_U32(tv,val) \
1294         DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
1295 #define DUK_TVAL_SET_I32(tv,val) \
1296         DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
1297 #define DUK_TVAL_SET_NUMBER(tv,val)  do { \
1298                 duk_tval *duk__tv; \
1299                 duk_double_t duk__dblval; \
1300                 duk__dblval = (val); \
1301                 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
1302                 duk__tv = (tv); \
1303                 duk__tv->t = DUK_TAG_NUMBER; \
1304                 duk__tv->v.d = duk__dblval; \
1305         } while (0)
1306 #define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
1307         DUK_TVAL_SET_NUMBER((tv), (d))
1308 #define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
1309         DUK_TVAL_SET_NUMBER((tv), (d))
1310 #define DUK_TVAL_CHKFAST_INPLACE_FAST(tv)  do { } while (0)
1311 #define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv)  do { } while (0)
1312 #endif  /* DUK_USE_FASTINT */
1313
1314 #define DUK_TVAL_SET_FASTINT(tv,i) \
1315         DUK_TVAL_SET_I48((tv), (i))  /* alias */
1316
1317 #define DUK_TVAL_SET_POINTER(tv,hptr)  do { \
1318                 duk_tval *duk__tv; \
1319                 duk__tv = (tv); \
1320                 duk__tv->t = DUK_TAG_POINTER; \
1321                 duk__tv->v.voidptr = (hptr); \
1322         } while (0)
1323
1324 #define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags)  do { \
1325                 duk_tval *duk__tv; \
1326                 duk__tv = (tv); \
1327                 duk__tv->t = DUK_TAG_LIGHTFUNC; \
1328                 duk__tv->v_extra = (flags); \
1329                 duk__tv->v.lightfunc = (duk_c_function) (fp); \
1330         } while (0)
1331
1332 #define DUK_TVAL_SET_STRING(tv,hptr)  do { \
1333                 duk_tval *duk__tv; \
1334                 duk__tv = (tv); \
1335                 duk__tv->t = DUK_TAG_STRING; \
1336                 duk__tv->v.hstring = (hptr); \
1337         } while (0)
1338
1339 #define DUK_TVAL_SET_OBJECT(tv,hptr)  do { \
1340                 duk_tval *duk__tv; \
1341                 duk__tv = (tv); \
1342                 duk__tv->t = DUK_TAG_OBJECT; \
1343                 duk__tv->v.hobject = (hptr); \
1344         } while (0)
1345
1346 #define DUK_TVAL_SET_BUFFER(tv,hptr)  do { \
1347                 duk_tval *duk__tv; \
1348                 duk__tv = (tv); \
1349                 duk__tv->t = DUK_TAG_BUFFER; \
1350                 duk__tv->v.hbuffer = (hptr); \
1351         } while (0)
1352
1353 #define DUK_TVAL_SET_NAN(tv)  do { \
1354                 /* in non-packed representation we don't care about which NaN is used */ \
1355                 duk_tval *duk__tv; \
1356                 duk__tv = (tv); \
1357                 duk__tv->t = DUK_TAG_NUMBER; \
1358                 duk__tv->v.d = DUK_DOUBLE_NAN; \
1359         } while (0)
1360
1361 #define DUK_TVAL_SET_TVAL(tv,x)            do { *(tv) = *(x); } while (0)
1362
1363 /* getters */
1364 #define DUK_TVAL_GET_BOOLEAN(tv)           ((duk_small_uint_t) (tv)->v.i)
1365 #if defined(DUK_USE_FASTINT)
1366 #define DUK_TVAL_GET_DOUBLE(tv)            ((tv)->v.d)
1367 #define DUK_TVAL_GET_FASTINT(tv)           ((tv)->v.fi)
1368 #define DUK_TVAL_GET_FASTINT_U32(tv)       ((duk_uint32_t) ((tv)->v.fi))
1369 #define DUK_TVAL_GET_FASTINT_I32(tv)       ((duk_int32_t) ((tv)->v.fi))
1370 #if 0
1371 #define DUK_TVAL_GET_NUMBER(tv)            (DUK_TVAL_IS_FASTINT((tv)) ? \
1372                                                (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \
1373                                                DUK_TVAL_GET_DOUBLE((tv)))
1374 #define DUK_TVAL_GET_NUMBER(tv)            duk_tval_get_number_unpacked((tv))
1375 #else
1376 /* This seems reasonable overall. */
1377 #define DUK_TVAL_GET_NUMBER(tv)            (DUK_TVAL_IS_FASTINT((tv)) ? \
1378                                                duk_tval_get_number_unpacked_fastint((tv)) : \
1379                                                DUK_TVAL_GET_DOUBLE((tv)))
1380 #endif
1381 #else
1382 #define DUK_TVAL_GET_NUMBER(tv)            ((tv)->v.d)
1383 #define DUK_TVAL_GET_DOUBLE(tv)            ((tv)->v.d)
1384 #endif  /* DUK_USE_FASTINT */
1385 #define DUK_TVAL_GET_POINTER(tv)           ((tv)->v.voidptr)
1386 #define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags)  do { \
1387                 (out_flags) = (duk_uint32_t) (tv)->v_extra; \
1388                 (out_fp) = (tv)->v.lightfunc; \
1389         } while (0)
1390 #define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
1391 #define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv)   ((duk_small_uint_t) ((tv)->v_extra))
1392 #define DUK_TVAL_GET_STRING(tv)            ((tv)->v.hstring)
1393 #define DUK_TVAL_GET_OBJECT(tv)            ((tv)->v.hobject)
1394 #define DUK_TVAL_GET_BUFFER(tv)            ((tv)->v.hbuffer)
1395 #define DUK_TVAL_GET_HEAPHDR(tv)           ((tv)->v.heaphdr)
1396
1397 /* decoding */
1398 #define DUK_TVAL_GET_TAG(tv)               ((tv)->t)
1399 #define DUK_TVAL_IS_UNDEFINED(tv)          ((tv)->t == DUK_TAG_UNDEFINED)
1400 #define DUK_TVAL_IS_UNUSED(tv)             ((tv)->t == DUK_TAG_UNUSED)
1401 #define DUK_TVAL_IS_NULL(tv)               ((tv)->t == DUK_TAG_NULL)
1402 #define DUK_TVAL_IS_BOOLEAN(tv)            ((tv)->t == DUK_TAG_BOOLEAN)
1403 #define DUK_TVAL_IS_BOOLEAN_TRUE(tv)       (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
1404 #define DUK_TVAL_IS_BOOLEAN_FALSE(tv)      (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
1405 #if defined(DUK_USE_FASTINT)
1406 #define DUK_TVAL_IS_DOUBLE(tv)             ((tv)->t == DUK_TAG_NUMBER)
1407 #define DUK_TVAL_IS_FASTINT(tv)            ((tv)->t == DUK_TAG_FASTINT)
1408 #define DUK_TVAL_IS_NUMBER(tv)             ((tv)->t == DUK_TAG_NUMBER || \
1409                                             (tv)->t == DUK_TAG_FASTINT)
1410 #else
1411 #define DUK_TVAL_IS_NUMBER(tv)             ((tv)->t == DUK_TAG_NUMBER)
1412 #define DUK_TVAL_IS_DOUBLE(tv)             DUK_TVAL_IS_NUMBER((tv))
1413 #endif  /* DUK_USE_FASTINT */
1414 #define DUK_TVAL_IS_POINTER(tv)            ((tv)->t == DUK_TAG_POINTER)
1415 #define DUK_TVAL_IS_LIGHTFUNC(tv)          ((tv)->t == DUK_TAG_LIGHTFUNC)
1416 #define DUK_TVAL_IS_STRING(tv)             ((tv)->t == DUK_TAG_STRING)
1417 #define DUK_TVAL_IS_OBJECT(tv)             ((tv)->t == DUK_TAG_OBJECT)
1418 #define DUK_TVAL_IS_BUFFER(tv)             ((tv)->t == DUK_TAG_BUFFER)
1419
1420 /* This is performance critical because it's needed for every DECREF.
1421  * Take advantage of the fact that the first heap allocated tag is 8,
1422  * so that bit 3 is set for all heap allocated tags (and never set for
1423  * non-heap-allocated tags).
1424  */
1425 #if 0
1426 #define DUK_TVAL_IS_HEAP_ALLOCATED(tv)     ((tv)->t >= DUK_TAG_STRING)
1427 #endif
1428 #define DUK_TVAL_IS_HEAP_ALLOCATED(tv)     ((tv)->t & 0x08)
1429
1430 #if defined(DUK_USE_FASTINT)
1431 #if 0
1432 DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv);
1433 #endif
1434 DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
1435 #endif
1436
1437 #endif  /* DUK_USE_PACKED_TVAL */
1438
1439 /*
1440  *  Convenience (independent of representation)
1441  */
1442
1443 #define DUK_TVAL_SET_BOOLEAN_TRUE(tv)        DUK_TVAL_SET_BOOLEAN((tv), 1)
1444 #define DUK_TVAL_SET_BOOLEAN_FALSE(tv)       DUK_TVAL_SET_BOOLEAN((tv), 0)
1445
1446 #define DUK_TVAL_STRING_IS_SYMBOL(tv) \
1447         DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv)))
1448
1449 /* Lightfunc flags packing and unpacking. */
1450 /* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##.
1451  * Avoid signed shifts due to portability limitations.
1452  */
1453 #define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
1454         ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8))
1455 #define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
1456         (((lf_flags) >> 4) & 0x0fU)
1457 #define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
1458         ((lf_flags) & 0x0fU)
1459 #define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
1460         ((((duk_small_uint_t) (magic)) & 0xffU) << 8) | ((length) << 4) | (nargs)
1461
1462 #define DUK_LFUNC_NARGS_VARARGS             0x0f   /* varargs marker */
1463 #define DUK_LFUNC_NARGS_MIN                 0x00
1464 #define DUK_LFUNC_NARGS_MAX                 0x0e   /* max, excl. varargs marker */
1465 #define DUK_LFUNC_LENGTH_MIN                0x00
1466 #define DUK_LFUNC_LENGTH_MAX                0x0f
1467 #define DUK_LFUNC_MAGIC_MIN                 (-0x80)
1468 #define DUK_LFUNC_MAGIC_MAX                 0x7f
1469
1470 /* fastint constants etc */
1471 #if defined(DUK_USE_FASTINT)
1472 #define DUK_FASTINT_MIN           (DUK_I64_CONSTANT(-0x800000000000))
1473 #define DUK_FASTINT_MAX           (DUK_I64_CONSTANT(0x7fffffffffff))
1474 #define DUK_FASTINT_BITS          48
1475
1476 DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x);
1477 DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x);
1478 #endif
1479
1480 #endif  /* DUK_TVAL_H_INCLUDED */
1481 /* #include duk_builtins.h */
1482 #line 1 "duk_builtins.h"
1483 /*
1484  *  Automatically generated by genbuiltins.py, do not edit!
1485  */
1486
1487 #if !defined(DUK_BUILTINS_H_INCLUDED)
1488 #define DUK_BUILTINS_H_INCLUDED
1489
1490 #if defined(DUK_USE_ROM_STRINGS)
1491 #error ROM support not enabled, rerun configure.py with --rom-support
1492 #else  /* DUK_USE_ROM_STRINGS */
1493 #define DUK_STRIDX_UC_UNDEFINED                                       0                              /* 'Undefined' */
1494 #define DUK_HEAP_STRING_UC_UNDEFINED(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
1495 #define DUK_HTHREAD_STRING_UC_UNDEFINED(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED)
1496 #define DUK_STRIDX_UC_NULL                                            1                              /* 'Null' */
1497 #define DUK_HEAP_STRING_UC_NULL(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
1498 #define DUK_HTHREAD_STRING_UC_NULL(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
1499 #define DUK_STRIDX_UC_SYMBOL                                          2                              /* 'Symbol' */
1500 #define DUK_HEAP_STRING_UC_SYMBOL(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL)
1501 #define DUK_HTHREAD_STRING_UC_SYMBOL(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL)
1502 #define DUK_STRIDX_UC_ARGUMENTS                                       3                              /* 'Arguments' */
1503 #define DUK_HEAP_STRING_UC_ARGUMENTS(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
1504 #define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
1505 #define DUK_STRIDX_UC_OBJECT                                          4                              /* 'Object' */
1506 #define DUK_HEAP_STRING_UC_OBJECT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
1507 #define DUK_HTHREAD_STRING_UC_OBJECT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
1508 #define DUK_STRIDX_UC_FUNCTION                                        5                              /* 'Function' */
1509 #define DUK_HEAP_STRING_UC_FUNCTION(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
1510 #define DUK_HTHREAD_STRING_UC_FUNCTION(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
1511 #define DUK_STRIDX_ARRAY                                              6                              /* 'Array' */
1512 #define DUK_HEAP_STRING_ARRAY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
1513 #define DUK_HTHREAD_STRING_ARRAY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
1514 #define DUK_STRIDX_UC_STRING                                          7                              /* 'String' */
1515 #define DUK_HEAP_STRING_UC_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
1516 #define DUK_HTHREAD_STRING_UC_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
1517 #define DUK_STRIDX_UC_BOOLEAN                                         8                              /* 'Boolean' */
1518 #define DUK_HEAP_STRING_UC_BOOLEAN(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
1519 #define DUK_HTHREAD_STRING_UC_BOOLEAN(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
1520 #define DUK_STRIDX_UC_NUMBER                                          9                              /* 'Number' */
1521 #define DUK_HEAP_STRING_UC_NUMBER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
1522 #define DUK_HTHREAD_STRING_UC_NUMBER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
1523 #define DUK_STRIDX_DATE                                               10                             /* 'Date' */
1524 #define DUK_HEAP_STRING_DATE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
1525 #define DUK_HTHREAD_STRING_DATE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
1526 #define DUK_STRIDX_REG_EXP                                            11                             /* 'RegExp' */
1527 #define DUK_HEAP_STRING_REG_EXP(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
1528 #define DUK_HTHREAD_STRING_REG_EXP(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
1529 #define DUK_STRIDX_UC_ERROR                                           12                             /* 'Error' */
1530 #define DUK_HEAP_STRING_UC_ERROR(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
1531 #define DUK_HTHREAD_STRING_UC_ERROR(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
1532 #define DUK_STRIDX_MATH                                               13                             /* 'Math' */
1533 #define DUK_HEAP_STRING_MATH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
1534 #define DUK_HTHREAD_STRING_MATH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
1535 #define DUK_STRIDX_JSON                                               14                             /* 'JSON' */
1536 #define DUK_HEAP_STRING_JSON(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
1537 #define DUK_HTHREAD_STRING_JSON(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
1538 #define DUK_STRIDX_EMPTY_STRING                                       15                             /* '' */
1539 #define DUK_HEAP_STRING_EMPTY_STRING(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
1540 #define DUK_HTHREAD_STRING_EMPTY_STRING(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
1541 #define DUK_STRIDX_ARRAY_BUFFER                                       16                             /* 'ArrayBuffer' */
1542 #define DUK_HEAP_STRING_ARRAY_BUFFER(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
1543 #define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
1544 #define DUK_STRIDX_DATA_VIEW                                          17                             /* 'DataView' */
1545 #define DUK_HEAP_STRING_DATA_VIEW(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
1546 #define DUK_HTHREAD_STRING_DATA_VIEW(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
1547 #define DUK_STRIDX_INT8_ARRAY                                         18                             /* 'Int8Array' */
1548 #define DUK_HEAP_STRING_INT8_ARRAY(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
1549 #define DUK_HTHREAD_STRING_INT8_ARRAY(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
1550 #define DUK_STRIDX_UINT8_ARRAY                                        19                             /* 'Uint8Array' */
1551 #define DUK_HEAP_STRING_UINT8_ARRAY(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
1552 #define DUK_HTHREAD_STRING_UINT8_ARRAY(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
1553 #define DUK_STRIDX_UINT8_CLAMPED_ARRAY                                20                             /* 'Uint8ClampedArray' */
1554 #define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap)                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
1555 #define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr)                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
1556 #define DUK_STRIDX_INT16_ARRAY                                        21                             /* 'Int16Array' */
1557 #define DUK_HEAP_STRING_INT16_ARRAY(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
1558 #define DUK_HTHREAD_STRING_INT16_ARRAY(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
1559 #define DUK_STRIDX_UINT16_ARRAY                                       22                             /* 'Uint16Array' */
1560 #define DUK_HEAP_STRING_UINT16_ARRAY(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
1561 #define DUK_HTHREAD_STRING_UINT16_ARRAY(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
1562 #define DUK_STRIDX_INT32_ARRAY                                        23                             /* 'Int32Array' */
1563 #define DUK_HEAP_STRING_INT32_ARRAY(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
1564 #define DUK_HTHREAD_STRING_INT32_ARRAY(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
1565 #define DUK_STRIDX_UINT32_ARRAY                                       24                             /* 'Uint32Array' */
1566 #define DUK_HEAP_STRING_UINT32_ARRAY(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
1567 #define DUK_HTHREAD_STRING_UINT32_ARRAY(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
1568 #define DUK_STRIDX_FLOAT32_ARRAY                                      25                             /* 'Float32Array' */
1569 #define DUK_HEAP_STRING_FLOAT32_ARRAY(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
1570 #define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
1571 #define DUK_STRIDX_FLOAT64_ARRAY                                      26                             /* 'Float64Array' */
1572 #define DUK_HEAP_STRING_FLOAT64_ARRAY(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
1573 #define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
1574 #define DUK_STRIDX_GLOBAL                                             27                             /* 'global' */
1575 #define DUK_HEAP_STRING_GLOBAL(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
1576 #define DUK_HTHREAD_STRING_GLOBAL(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
1577 #define DUK_STRIDX_OBJ_ENV                                            28                             /* 'ObjEnv' */
1578 #define DUK_HEAP_STRING_OBJ_ENV(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
1579 #define DUK_HTHREAD_STRING_OBJ_ENV(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
1580 #define DUK_STRIDX_DEC_ENV                                            29                             /* 'DecEnv' */
1581 #define DUK_HEAP_STRING_DEC_ENV(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
1582 #define DUK_HTHREAD_STRING_DEC_ENV(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
1583 #define DUK_STRIDX_UC_BUFFER                                          30                             /* 'Buffer' */
1584 #define DUK_HEAP_STRING_UC_BUFFER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
1585 #define DUK_HTHREAD_STRING_UC_BUFFER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
1586 #define DUK_STRIDX_UC_POINTER                                         31                             /* 'Pointer' */
1587 #define DUK_HEAP_STRING_UC_POINTER(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
1588 #define DUK_HTHREAD_STRING_UC_POINTER(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
1589 #define DUK_STRIDX_UC_THREAD                                          32                             /* 'Thread' */
1590 #define DUK_HEAP_STRING_UC_THREAD(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
1591 #define DUK_HTHREAD_STRING_UC_THREAD(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
1592 #define DUK_STRIDX_EVAL                                               33                             /* 'eval' */
1593 #define DUK_HEAP_STRING_EVAL(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
1594 #define DUK_HTHREAD_STRING_EVAL(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
1595 #define DUK_STRIDX_VALUE                                              34                             /* 'value' */
1596 #define DUK_HEAP_STRING_VALUE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
1597 #define DUK_HTHREAD_STRING_VALUE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
1598 #define DUK_STRIDX_WRITABLE                                           35                             /* 'writable' */
1599 #define DUK_HEAP_STRING_WRITABLE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
1600 #define DUK_HTHREAD_STRING_WRITABLE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
1601 #define DUK_STRIDX_CONFIGURABLE                                       36                             /* 'configurable' */
1602 #define DUK_HEAP_STRING_CONFIGURABLE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
1603 #define DUK_HTHREAD_STRING_CONFIGURABLE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
1604 #define DUK_STRIDX_ENUMERABLE                                         37                             /* 'enumerable' */
1605 #define DUK_HEAP_STRING_ENUMERABLE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
1606 #define DUK_HTHREAD_STRING_ENUMERABLE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
1607 #define DUK_STRIDX_JOIN                                               38                             /* 'join' */
1608 #define DUK_HEAP_STRING_JOIN(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
1609 #define DUK_HTHREAD_STRING_JOIN(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
1610 #define DUK_STRIDX_TO_LOCALE_STRING                                   39                             /* 'toLocaleString' */
1611 #define DUK_HEAP_STRING_TO_LOCALE_STRING(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
1612 #define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
1613 #define DUK_STRIDX_VALUE_OF                                           40                             /* 'valueOf' */
1614 #define DUK_HEAP_STRING_VALUE_OF(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
1615 #define DUK_HTHREAD_STRING_VALUE_OF(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
1616 #define DUK_STRIDX_TO_UTC_STRING                                      41                             /* 'toUTCString' */
1617 #define DUK_HEAP_STRING_TO_UTC_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
1618 #define DUK_HTHREAD_STRING_TO_UTC_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
1619 #define DUK_STRIDX_TO_ISO_STRING                                      42                             /* 'toISOString' */
1620 #define DUK_HEAP_STRING_TO_ISO_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
1621 #define DUK_HTHREAD_STRING_TO_ISO_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
1622 #define DUK_STRIDX_TO_GMT_STRING                                      43                             /* 'toGMTString' */
1623 #define DUK_HEAP_STRING_TO_GMT_STRING(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
1624 #define DUK_HTHREAD_STRING_TO_GMT_STRING(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
1625 #define DUK_STRIDX_SOURCE                                             44                             /* 'source' */
1626 #define DUK_HEAP_STRING_SOURCE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
1627 #define DUK_HTHREAD_STRING_SOURCE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
1628 #define DUK_STRIDX_IGNORE_CASE                                        45                             /* 'ignoreCase' */
1629 #define DUK_HEAP_STRING_IGNORE_CASE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
1630 #define DUK_HTHREAD_STRING_IGNORE_CASE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
1631 #define DUK_STRIDX_MULTILINE                                          46                             /* 'multiline' */
1632 #define DUK_HEAP_STRING_MULTILINE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
1633 #define DUK_HTHREAD_STRING_MULTILINE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
1634 #define DUK_STRIDX_LAST_INDEX                                         47                             /* 'lastIndex' */
1635 #define DUK_HEAP_STRING_LAST_INDEX(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
1636 #define DUK_HTHREAD_STRING_LAST_INDEX(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
1637 #define DUK_STRIDX_FLAGS                                              48                             /* 'flags' */
1638 #define DUK_HEAP_STRING_FLAGS(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS)
1639 #define DUK_HTHREAD_STRING_FLAGS(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS)
1640 #define DUK_STRIDX_INDEX                                              49                             /* 'index' */
1641 #define DUK_HEAP_STRING_INDEX(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
1642 #define DUK_HTHREAD_STRING_INDEX(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
1643 #define DUK_STRIDX_PROTOTYPE                                          50                             /* 'prototype' */
1644 #define DUK_HEAP_STRING_PROTOTYPE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
1645 #define DUK_HTHREAD_STRING_PROTOTYPE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
1646 #define DUK_STRIDX_CONSTRUCTOR                                        51                             /* 'constructor' */
1647 #define DUK_HEAP_STRING_CONSTRUCTOR(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
1648 #define DUK_HTHREAD_STRING_CONSTRUCTOR(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
1649 #define DUK_STRIDX_MESSAGE                                            52                             /* 'message' */
1650 #define DUK_HEAP_STRING_MESSAGE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
1651 #define DUK_HTHREAD_STRING_MESSAGE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
1652 #define DUK_STRIDX_LC_BOOLEAN                                         53                             /* 'boolean' */
1653 #define DUK_HEAP_STRING_LC_BOOLEAN(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
1654 #define DUK_HTHREAD_STRING_LC_BOOLEAN(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
1655 #define DUK_STRIDX_LC_NUMBER                                          54                             /* 'number' */
1656 #define DUK_HEAP_STRING_LC_NUMBER(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
1657 #define DUK_HTHREAD_STRING_LC_NUMBER(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
1658 #define DUK_STRIDX_LC_STRING                                          55                             /* 'string' */
1659 #define DUK_HEAP_STRING_LC_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
1660 #define DUK_HTHREAD_STRING_LC_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
1661 #define DUK_STRIDX_LC_SYMBOL                                          56                             /* 'symbol' */
1662 #define DUK_HEAP_STRING_LC_SYMBOL(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL)
1663 #define DUK_HTHREAD_STRING_LC_SYMBOL(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL)
1664 #define DUK_STRIDX_LC_OBJECT                                          57                             /* 'object' */
1665 #define DUK_HEAP_STRING_LC_OBJECT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
1666 #define DUK_HTHREAD_STRING_LC_OBJECT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
1667 #define DUK_STRIDX_LC_UNDEFINED                                       58                             /* 'undefined' */
1668 #define DUK_HEAP_STRING_LC_UNDEFINED(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
1669 #define DUK_HTHREAD_STRING_LC_UNDEFINED(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
1670 #define DUK_STRIDX_NAN                                                59                             /* 'NaN' */
1671 #define DUK_HEAP_STRING_NAN(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
1672 #define DUK_HTHREAD_STRING_NAN(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
1673 #define DUK_STRIDX_INFINITY                                           60                             /* 'Infinity' */
1674 #define DUK_HEAP_STRING_INFINITY(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
1675 #define DUK_HTHREAD_STRING_INFINITY(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
1676 #define DUK_STRIDX_MINUS_INFINITY                                     61                             /* '-Infinity' */
1677 #define DUK_HEAP_STRING_MINUS_INFINITY(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
1678 #define DUK_HTHREAD_STRING_MINUS_INFINITY(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
1679 #define DUK_STRIDX_MINUS_ZERO                                         62                             /* '-0' */
1680 #define DUK_HEAP_STRING_MINUS_ZERO(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
1681 #define DUK_HTHREAD_STRING_MINUS_ZERO(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
1682 #define DUK_STRIDX_COMMA                                              63                             /* ',' */
1683 #define DUK_HEAP_STRING_COMMA(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
1684 #define DUK_HTHREAD_STRING_COMMA(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
1685 #define DUK_STRIDX_NEWLINE_4SPACE                                     64                             /* '\n    ' */
1686 #define DUK_HEAP_STRING_NEWLINE_4SPACE(heap)                          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
1687 #define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr)                        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
1688 #define DUK_STRIDX_BRACKETED_ELLIPSIS                                 65                             /* '[...]' */
1689 #define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
1690 #define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
1691 #define DUK_STRIDX_INVALID_DATE                                       66                             /* 'Invalid Date' */
1692 #define DUK_HEAP_STRING_INVALID_DATE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
1693 #define DUK_HTHREAD_STRING_INVALID_DATE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
1694 #define DUK_STRIDX_LC_ARGUMENTS                                       67                             /* 'arguments' */
1695 #define DUK_HEAP_STRING_LC_ARGUMENTS(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
1696 #define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
1697 #define DUK_STRIDX_CALLEE                                             68                             /* 'callee' */
1698 #define DUK_HEAP_STRING_CALLEE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
1699 #define DUK_HTHREAD_STRING_CALLEE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
1700 #define DUK_STRIDX_CALLER                                             69                             /* 'caller' */
1701 #define DUK_HEAP_STRING_CALLER(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
1702 #define DUK_HTHREAD_STRING_CALLER(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
1703 #define DUK_STRIDX_APPLY                                              70                             /* 'apply' */
1704 #define DUK_HEAP_STRING_APPLY(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_APPLY)
1705 #define DUK_HTHREAD_STRING_APPLY(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_APPLY)
1706 #define DUK_STRIDX_CONSTRUCT                                          71                             /* 'construct' */
1707 #define DUK_HEAP_STRING_CONSTRUCT(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCT)
1708 #define DUK_HTHREAD_STRING_CONSTRUCT(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCT)
1709 #define DUK_STRIDX_DELETE_PROPERTY                                    72                             /* 'deleteProperty' */
1710 #define DUK_HEAP_STRING_DELETE_PROPERTY(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
1711 #define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
1712 #define DUK_STRIDX_GET                                                73                             /* 'get' */
1713 #define DUK_HEAP_STRING_GET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
1714 #define DUK_HTHREAD_STRING_GET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
1715 #define DUK_STRIDX_HAS                                                74                             /* 'has' */
1716 #define DUK_HEAP_STRING_HAS(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
1717 #define DUK_HTHREAD_STRING_HAS(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
1718 #define DUK_STRIDX_OWN_KEYS                                           75                             /* 'ownKeys' */
1719 #define DUK_HEAP_STRING_OWN_KEYS(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
1720 #define DUK_HTHREAD_STRING_OWN_KEYS(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
1721 #define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE                      76                             /* '\x81Symbol.toPrimitive\xff' */
1722 #define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(heap)           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)
1723 #define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_PRIMITIVE(thr)         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)
1724 #define DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE                      77                             /* '\x81Symbol.hasInstance\xff' */
1725 #define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(heap)           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)
1726 #define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_HAS_INSTANCE(thr)         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)
1727 #define DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG                     78                             /* '\x81Symbol.toStringTag\xff' */
1728 #define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(heap)          DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG)
1729 #define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_TO_STRING_TAG(thr)        DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG)
1730 #define DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE              79                             /* '\x81Symbol.isConcatSpreadable\xff' */
1731 #define DUK_HEAP_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(heap)   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE)
1732 #define DUK_HTHREAD_STRING_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE(thr)  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE)
1733 #define DUK_STRIDX_SET_PROTOTYPE_OF                                   80                             /* 'setPrototypeOf' */
1734 #define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap)                        DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
1735 #define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr)                      DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
1736 #define DUK_STRIDX___PROTO__                                          81                             /* '__proto__' */
1737 #define DUK_HEAP_STRING___PROTO__(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
1738 #define DUK_HTHREAD_STRING___PROTO__(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
1739 #define DUK_STRIDX_TO_STRING                                          82                             /* 'toString' */
1740 #define DUK_HEAP_STRING_TO_STRING(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
1741 #define DUK_HTHREAD_STRING_TO_STRING(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
1742 #define DUK_STRIDX_TO_JSON                                            83                             /* 'toJSON' */
1743 #define DUK_HEAP_STRING_TO_JSON(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
1744 #define DUK_HTHREAD_STRING_TO_JSON(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
1745 #define DUK_STRIDX_TYPE                                               84                             /* 'type' */
1746 #define DUK_HEAP_STRING_TYPE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
1747 #define DUK_HTHREAD_STRING_TYPE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
1748 #define DUK_STRIDX_DATA                                               85                             /* 'data' */
1749 #define DUK_HEAP_STRING_DATA(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
1750 #define DUK_HTHREAD_STRING_DATA(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
1751 #define DUK_STRIDX_LENGTH                                             86                             /* 'length' */
1752 #define DUK_HEAP_STRING_LENGTH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
1753 #define DUK_HTHREAD_STRING_LENGTH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
1754 #define DUK_STRIDX_SET                                                87                             /* 'set' */
1755 #define DUK_HEAP_STRING_SET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
1756 #define DUK_HTHREAD_STRING_SET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
1757 #define DUK_STRIDX_STACK                                              88                             /* 'stack' */
1758 #define DUK_HEAP_STRING_STACK(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
1759 #define DUK_HTHREAD_STRING_STACK(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
1760 #define DUK_STRIDX_PC                                                 89                             /* 'pc' */
1761 #define DUK_HEAP_STRING_PC(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
1762 #define DUK_HTHREAD_STRING_PC(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
1763 #define DUK_STRIDX_LINE_NUMBER                                        90                             /* 'lineNumber' */
1764 #define DUK_HEAP_STRING_LINE_NUMBER(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
1765 #define DUK_HTHREAD_STRING_LINE_NUMBER(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
1766 #define DUK_STRIDX_INT_TRACEDATA                                      91                             /* '\x82Tracedata' */
1767 #define DUK_HEAP_STRING_INT_TRACEDATA(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
1768 #define DUK_HTHREAD_STRING_INT_TRACEDATA(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
1769 #define DUK_STRIDX_NAME                                               92                             /* 'name' */
1770 #define DUK_HEAP_STRING_NAME(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
1771 #define DUK_HTHREAD_STRING_NAME(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
1772 #define DUK_STRIDX_FILE_NAME                                          93                             /* 'fileName' */
1773 #define DUK_HEAP_STRING_FILE_NAME(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
1774 #define DUK_HTHREAD_STRING_FILE_NAME(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
1775 #define DUK_STRIDX_LC_POINTER                                         94                             /* 'pointer' */
1776 #define DUK_HEAP_STRING_LC_POINTER(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
1777 #define DUK_HTHREAD_STRING_LC_POINTER(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
1778 #define DUK_STRIDX_INT_TARGET                                         95                             /* '\x82Target' */
1779 #define DUK_HEAP_STRING_INT_TARGET(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
1780 #define DUK_HTHREAD_STRING_INT_TARGET(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
1781 #define DUK_STRIDX_INT_NEXT                                           96                             /* '\x82Next' */
1782 #define DUK_HEAP_STRING_INT_NEXT(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
1783 #define DUK_HTHREAD_STRING_INT_NEXT(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
1784 #define DUK_STRIDX_INT_BYTECODE                                       97                             /* '\x82Bytecode' */
1785 #define DUK_HEAP_STRING_INT_BYTECODE(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
1786 #define DUK_HTHREAD_STRING_INT_BYTECODE(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
1787 #define DUK_STRIDX_INT_FORMALS                                        98                             /* '\x82Formals' */
1788 #define DUK_HEAP_STRING_INT_FORMALS(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
1789 #define DUK_HTHREAD_STRING_INT_FORMALS(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
1790 #define DUK_STRIDX_INT_VARMAP                                         99                             /* '\x82Varmap' */
1791 #define DUK_HEAP_STRING_INT_VARMAP(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
1792 #define DUK_HTHREAD_STRING_INT_VARMAP(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
1793 #define DUK_STRIDX_INT_SOURCE                                         100                            /* '\x82Source' */
1794 #define DUK_HEAP_STRING_INT_SOURCE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
1795 #define DUK_HTHREAD_STRING_INT_SOURCE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
1796 #define DUK_STRIDX_INT_PC2LINE                                        101                            /* '\x82Pc2line' */
1797 #define DUK_HEAP_STRING_INT_PC2LINE(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
1798 #define DUK_HTHREAD_STRING_INT_PC2LINE(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
1799 #define DUK_STRIDX_INT_MAP                                            102                            /* '\x82Map' */
1800 #define DUK_HEAP_STRING_INT_MAP(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
1801 #define DUK_HTHREAD_STRING_INT_MAP(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
1802 #define DUK_STRIDX_INT_VARENV                                         103                            /* '\x82Varenv' */
1803 #define DUK_HEAP_STRING_INT_VARENV(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
1804 #define DUK_HTHREAD_STRING_INT_VARENV(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
1805 #define DUK_STRIDX_INT_FINALIZER                                      104                            /* '\x82Finalizer' */
1806 #define DUK_HEAP_STRING_INT_FINALIZER(heap)                           DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
1807 #define DUK_HTHREAD_STRING_INT_FINALIZER(thr)                         DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
1808 #define DUK_STRIDX_INT_VALUE                                          105                            /* '\x82Value' */
1809 #define DUK_HEAP_STRING_INT_VALUE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
1810 #define DUK_HTHREAD_STRING_INT_VALUE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
1811 #define DUK_STRIDX_COMPILE                                            106                            /* 'compile' */
1812 #define DUK_HEAP_STRING_COMPILE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
1813 #define DUK_HTHREAD_STRING_COMPILE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
1814 #define DUK_STRIDX_INPUT                                              107                            /* 'input' */
1815 #define DUK_HEAP_STRING_INPUT(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
1816 #define DUK_HTHREAD_STRING_INPUT(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
1817 #define DUK_STRIDX_ERR_CREATE                                         108                            /* 'errCreate' */
1818 #define DUK_HEAP_STRING_ERR_CREATE(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
1819 #define DUK_HTHREAD_STRING_ERR_CREATE(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
1820 #define DUK_STRIDX_ERR_THROW                                          109                            /* 'errThrow' */
1821 #define DUK_HEAP_STRING_ERR_THROW(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
1822 #define DUK_HTHREAD_STRING_ERR_THROW(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
1823 #define DUK_STRIDX_ENV                                                110                            /* 'env' */
1824 #define DUK_HEAP_STRING_ENV(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
1825 #define DUK_HTHREAD_STRING_ENV(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
1826 #define DUK_STRIDX_HEX                                                111                            /* 'hex' */
1827 #define DUK_HEAP_STRING_HEX(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
1828 #define DUK_HTHREAD_STRING_HEX(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
1829 #define DUK_STRIDX_BASE64                                             112                            /* 'base64' */
1830 #define DUK_HEAP_STRING_BASE64(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
1831 #define DUK_HTHREAD_STRING_BASE64(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
1832 #define DUK_STRIDX_JX                                                 113                            /* 'jx' */
1833 #define DUK_HEAP_STRING_JX(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
1834 #define DUK_HTHREAD_STRING_JX(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
1835 #define DUK_STRIDX_JC                                                 114                            /* 'jc' */
1836 #define DUK_HEAP_STRING_JC(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
1837 #define DUK_HTHREAD_STRING_JC(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
1838 #define DUK_STRIDX_JSON_EXT_UNDEFINED                                 115                            /* '{"_undef":true}' */
1839 #define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
1840 #define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
1841 #define DUK_STRIDX_JSON_EXT_NAN                                       116                            /* '{"_nan":true}' */
1842 #define DUK_HEAP_STRING_JSON_EXT_NAN(heap)                            DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
1843 #define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr)                          DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
1844 #define DUK_STRIDX_JSON_EXT_POSINF                                    117                            /* '{"_inf":true}' */
1845 #define DUK_HEAP_STRING_JSON_EXT_POSINF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
1846 #define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
1847 #define DUK_STRIDX_JSON_EXT_NEGINF                                    118                            /* '{"_ninf":true}' */
1848 #define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap)                         DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
1849 #define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr)                       DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
1850 #define DUK_STRIDX_JSON_EXT_FUNCTION1                                 119                            /* '{"_func":true}' */
1851 #define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
1852 #define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
1853 #define DUK_STRIDX_JSON_EXT_FUNCTION2                                 120                            /* '{_func:true}' */
1854 #define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap)                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
1855 #define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr)                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
1856 #define DUK_STRIDX_BREAK                                              121                            /* 'break' */
1857 #define DUK_HEAP_STRING_BREAK(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
1858 #define DUK_HTHREAD_STRING_BREAK(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
1859 #define DUK_STRIDX_CASE                                               122                            /* 'case' */
1860 #define DUK_HEAP_STRING_CASE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
1861 #define DUK_HTHREAD_STRING_CASE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
1862 #define DUK_STRIDX_CATCH                                              123                            /* 'catch' */
1863 #define DUK_HEAP_STRING_CATCH(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
1864 #define DUK_HTHREAD_STRING_CATCH(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
1865 #define DUK_STRIDX_CONTINUE                                           124                            /* 'continue' */
1866 #define DUK_HEAP_STRING_CONTINUE(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
1867 #define DUK_HTHREAD_STRING_CONTINUE(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
1868 #define DUK_STRIDX_DEBUGGER                                           125                            /* 'debugger' */
1869 #define DUK_HEAP_STRING_DEBUGGER(heap)                                DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
1870 #define DUK_HTHREAD_STRING_DEBUGGER(thr)                              DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
1871 #define DUK_STRIDX_DEFAULT                                            126                            /* 'default' */
1872 #define DUK_HEAP_STRING_DEFAULT(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
1873 #define DUK_HTHREAD_STRING_DEFAULT(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
1874 #define DUK_STRIDX_DELETE                                             127                            /* 'delete' */
1875 #define DUK_HEAP_STRING_DELETE(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
1876 #define DUK_HTHREAD_STRING_DELETE(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
1877 #define DUK_STRIDX_DO                                                 128                            /* 'do' */
1878 #define DUK_HEAP_STRING_DO(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
1879 #define DUK_HTHREAD_STRING_DO(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
1880 #define DUK_STRIDX_ELSE                                               129                            /* 'else' */
1881 #define DUK_HEAP_STRING_ELSE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
1882 #define DUK_HTHREAD_STRING_ELSE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
1883 #define DUK_STRIDX_FINALLY                                            130                            /* 'finally' */
1884 #define DUK_HEAP_STRING_FINALLY(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
1885 #define DUK_HTHREAD_STRING_FINALLY(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
1886 #define DUK_STRIDX_FOR                                                131                            /* 'for' */
1887 #define DUK_HEAP_STRING_FOR(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
1888 #define DUK_HTHREAD_STRING_FOR(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
1889 #define DUK_STRIDX_LC_FUNCTION                                        132                            /* 'function' */
1890 #define DUK_HEAP_STRING_LC_FUNCTION(heap)                             DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
1891 #define DUK_HTHREAD_STRING_LC_FUNCTION(thr)                           DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
1892 #define DUK_STRIDX_IF                                                 133                            /* 'if' */
1893 #define DUK_HEAP_STRING_IF(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
1894 #define DUK_HTHREAD_STRING_IF(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
1895 #define DUK_STRIDX_IN                                                 134                            /* 'in' */
1896 #define DUK_HEAP_STRING_IN(heap)                                      DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
1897 #define DUK_HTHREAD_STRING_IN(thr)                                    DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
1898 #define DUK_STRIDX_INSTANCEOF                                         135                            /* 'instanceof' */
1899 #define DUK_HEAP_STRING_INSTANCEOF(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
1900 #define DUK_HTHREAD_STRING_INSTANCEOF(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
1901 #define DUK_STRIDX_NEW                                                136                            /* 'new' */
1902 #define DUK_HEAP_STRING_NEW(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
1903 #define DUK_HTHREAD_STRING_NEW(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
1904 #define DUK_STRIDX_RETURN                                             137                            /* 'return' */
1905 #define DUK_HEAP_STRING_RETURN(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
1906 #define DUK_HTHREAD_STRING_RETURN(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
1907 #define DUK_STRIDX_SWITCH                                             138                            /* 'switch' */
1908 #define DUK_HEAP_STRING_SWITCH(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
1909 #define DUK_HTHREAD_STRING_SWITCH(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
1910 #define DUK_STRIDX_THIS                                               139                            /* 'this' */
1911 #define DUK_HEAP_STRING_THIS(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
1912 #define DUK_HTHREAD_STRING_THIS(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
1913 #define DUK_STRIDX_THROW                                              140                            /* 'throw' */
1914 #define DUK_HEAP_STRING_THROW(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
1915 #define DUK_HTHREAD_STRING_THROW(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
1916 #define DUK_STRIDX_TRY                                                141                            /* 'try' */
1917 #define DUK_HEAP_STRING_TRY(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
1918 #define DUK_HTHREAD_STRING_TRY(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
1919 #define DUK_STRIDX_TYPEOF                                             142                            /* 'typeof' */
1920 #define DUK_HEAP_STRING_TYPEOF(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
1921 #define DUK_HTHREAD_STRING_TYPEOF(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
1922 #define DUK_STRIDX_VAR                                                143                            /* 'var' */
1923 #define DUK_HEAP_STRING_VAR(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
1924 #define DUK_HTHREAD_STRING_VAR(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
1925 #define DUK_STRIDX_CONST                                              144                            /* 'const' */
1926 #define DUK_HEAP_STRING_CONST(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
1927 #define DUK_HTHREAD_STRING_CONST(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
1928 #define DUK_STRIDX_VOID                                               145                            /* 'void' */
1929 #define DUK_HEAP_STRING_VOID(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
1930 #define DUK_HTHREAD_STRING_VOID(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
1931 #define DUK_STRIDX_WHILE                                              146                            /* 'while' */
1932 #define DUK_HEAP_STRING_WHILE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
1933 #define DUK_HTHREAD_STRING_WHILE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
1934 #define DUK_STRIDX_WITH                                               147                            /* 'with' */
1935 #define DUK_HEAP_STRING_WITH(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
1936 #define DUK_HTHREAD_STRING_WITH(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
1937 #define DUK_STRIDX_CLASS                                              148                            /* 'class' */
1938 #define DUK_HEAP_STRING_CLASS(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
1939 #define DUK_HTHREAD_STRING_CLASS(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
1940 #define DUK_STRIDX_ENUM                                               149                            /* 'enum' */
1941 #define DUK_HEAP_STRING_ENUM(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
1942 #define DUK_HTHREAD_STRING_ENUM(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
1943 #define DUK_STRIDX_EXPORT                                             150                            /* 'export' */
1944 #define DUK_HEAP_STRING_EXPORT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
1945 #define DUK_HTHREAD_STRING_EXPORT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
1946 #define DUK_STRIDX_EXTENDS                                            151                            /* 'extends' */
1947 #define DUK_HEAP_STRING_EXTENDS(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
1948 #define DUK_HTHREAD_STRING_EXTENDS(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
1949 #define DUK_STRIDX_IMPORT                                             152                            /* 'import' */
1950 #define DUK_HEAP_STRING_IMPORT(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
1951 #define DUK_HTHREAD_STRING_IMPORT(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
1952 #define DUK_STRIDX_SUPER                                              153                            /* 'super' */
1953 #define DUK_HEAP_STRING_SUPER(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
1954 #define DUK_HTHREAD_STRING_SUPER(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
1955 #define DUK_STRIDX_LC_NULL                                            154                            /* 'null' */
1956 #define DUK_HEAP_STRING_LC_NULL(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
1957 #define DUK_HTHREAD_STRING_LC_NULL(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
1958 #define DUK_STRIDX_TRUE                                               155                            /* 'true' */
1959 #define DUK_HEAP_STRING_TRUE(heap)                                    DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
1960 #define DUK_HTHREAD_STRING_TRUE(thr)                                  DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
1961 #define DUK_STRIDX_FALSE                                              156                            /* 'false' */
1962 #define DUK_HEAP_STRING_FALSE(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
1963 #define DUK_HTHREAD_STRING_FALSE(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
1964 #define DUK_STRIDX_IMPLEMENTS                                         157                            /* 'implements' */
1965 #define DUK_HEAP_STRING_IMPLEMENTS(heap)                              DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
1966 #define DUK_HTHREAD_STRING_IMPLEMENTS(thr)                            DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
1967 #define DUK_STRIDX_INTERFACE                                          158                            /* 'interface' */
1968 #define DUK_HEAP_STRING_INTERFACE(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
1969 #define DUK_HTHREAD_STRING_INTERFACE(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
1970 #define DUK_STRIDX_LET                                                159                            /* 'let' */
1971 #define DUK_HEAP_STRING_LET(heap)                                     DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
1972 #define DUK_HTHREAD_STRING_LET(thr)                                   DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
1973 #define DUK_STRIDX_PACKAGE                                            160                            /* 'package' */
1974 #define DUK_HEAP_STRING_PACKAGE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
1975 #define DUK_HTHREAD_STRING_PACKAGE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
1976 #define DUK_STRIDX_PRIVATE                                            161                            /* 'private' */
1977 #define DUK_HEAP_STRING_PRIVATE(heap)                                 DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
1978 #define DUK_HTHREAD_STRING_PRIVATE(thr)                               DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
1979 #define DUK_STRIDX_PROTECTED                                          162                            /* 'protected' */
1980 #define DUK_HEAP_STRING_PROTECTED(heap)                               DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
1981 #define DUK_HTHREAD_STRING_PROTECTED(thr)                             DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
1982 #define DUK_STRIDX_PUBLIC                                             163                            /* 'public' */
1983 #define DUK_HEAP_STRING_PUBLIC(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
1984 #define DUK_HTHREAD_STRING_PUBLIC(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
1985 #define DUK_STRIDX_STATIC                                             164                            /* 'static' */
1986 #define DUK_HEAP_STRING_STATIC(heap)                                  DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
1987 #define DUK_HTHREAD_STRING_STATIC(thr)                                DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
1988 #define DUK_STRIDX_YIELD                                              165                            /* 'yield' */
1989 #define DUK_HEAP_STRING_YIELD(heap)                                   DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
1990 #define DUK_HTHREAD_STRING_YIELD(thr)                                 DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
1991
1992 #define DUK_HEAP_NUM_STRINGS                                          166
1993 #define DUK_STRIDX_START_RESERVED                                     121
1994 #define DUK_STRIDX_START_STRICT_RESERVED                              157
1995 #define DUK_STRIDX_END_RESERVED                                       166                            /* exclusive endpoint */
1996
1997 /* To convert a heap stridx to a token number, subtract
1998  * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
1999  */
2000 #if !defined(DUK_SINGLE_FILE)
2001 DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[967];
2002 #endif  /* !DUK_SINGLE_FILE */
2003 #define DUK_STRDATA_MAX_STRLEN                                        27
2004 #define DUK_STRDATA_DATA_LENGTH                                       967
2005 #endif  /* DUK_USE_ROM_STRINGS */
2006
2007 #if defined(DUK_USE_ROM_OBJECTS)
2008 #error RAM support not enabled, rerun configure.py with --ram-support
2009 #else  /* DUK_USE_ROM_OBJECTS */
2010 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
2011 DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
2012 DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
2013 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx);
2014 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx);
2015 DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx);
2016 DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx);
2017 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
2018 DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
2019 DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
2020 DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
2021 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
2022 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
2023 DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
2024 DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
2025 DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
2026 DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
2027 DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
2028 DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
2029 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
2030 DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx);
2031 DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx);
2032 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
2033 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
2034 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
2035 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
2036 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx);
2037 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
2038 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
2039 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
2040 DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
2041 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
2042 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
2043 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
2044 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
2045 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx);
2046 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
2047 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
2048 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
2049 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx);
2050 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
2051 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
2052 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
2053 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx);
2054 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
2055 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
2056 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
2057 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
2058 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
2059 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
2060 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_context *ctx);
2061 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_context *ctx);
2062 DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
2063 DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
2064 DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
2065 DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
2066 DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_length(duk_context *ctx);
2067 DUK_INTERNAL_DECL duk_ret_t duk_bi_native_function_name(duk_context *ctx);
2068 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
2069 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
2070 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
2071 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx);
2072 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx);
2073 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx);
2074 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx);
2075 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx);
2076 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx);
2077 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx);
2078 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx);
2079 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx);
2080 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx);
2081 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
2082 DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
2083 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
2084 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx);
2085 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
2086 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
2087 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
2088 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx);
2089 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx);
2090 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx);
2091 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx);
2092 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx);
2093 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx);
2094 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx);
2095 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
2096 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
2097 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
2098 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
2099 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx);
2100 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_context *ctx);
2101 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_includes(duk_context *ctx);
2102 DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
2103 DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
2104 DUK_INTERNAL_DECL duk_ret_t duk_bi_number_check_shared(duk_context *ctx);
2105 DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
2106 DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
2107 DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
2108 DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx);
2109 DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx);
2110 DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx);
2111 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx);
2112 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx);
2113 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx);
2114 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx);
2115 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx);
2116 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx);
2117 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx);
2118 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx);
2119 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
2120 DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
2121 DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
2122 DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
2123 DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx);
2124 DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx);
2125 DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx);
2126 DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
2127 DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
2128 DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
2129 DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
2130 DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
2131 DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
2132 DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
2133 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
2134 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
2135 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_clz32(duk_context *ctx);
2136 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx);
2137 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_imul(duk_context *ctx);
2138 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
2139 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
2140 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
2141 DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_sign(duk_context *ctx);
2142 DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
2143 DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
2144 DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
2145 DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
2146 DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx);
2147 DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx);
2148 DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx);
2149 DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx);
2150 DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
2151 DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
2152 DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
2153 DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
2154 DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
2155 DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_apply(duk_context *ctx);
2156 DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_construct(duk_context *ctx);
2157 DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx);
2158 DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx);
2159 DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx);
2160 DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx);
2161 DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
2162 DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx);
2163 DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
2164 DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx);
2165 DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx);
2166 DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
2167 DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
2168 DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
2169 DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx);
2170 DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx);
2171 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
2172 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
2173 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
2174 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx);
2175 DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx);
2176 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx);
2177 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
2178 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
2179 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
2180 DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
2181 DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx);
2182 DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx);
2183 DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx);
2184 DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx);
2185 DUK_INTERNAL_DECL duk_ret_t duk_bi_performance_now(duk_context *ctx);
2186 #if !defined(DUK_SINGLE_FILE)
2187 DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[177];
2188 #endif  /* !DUK_SINGLE_FILE */
2189 #define DUK_BIDX_GLOBAL                                               0
2190 #define DUK_BIDX_GLOBAL_ENV                                           1
2191 #define DUK_BIDX_OBJECT_CONSTRUCTOR                                   2
2192 #define DUK_BIDX_OBJECT_PROTOTYPE                                     3
2193 #define DUK_BIDX_FUNCTION_CONSTRUCTOR                                 4
2194 #define DUK_BIDX_FUNCTION_PROTOTYPE                                   5
2195 #define DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE                            6
2196 #define DUK_BIDX_ARRAY_CONSTRUCTOR                                    7
2197 #define DUK_BIDX_ARRAY_PROTOTYPE                                      8
2198 #define DUK_BIDX_STRING_CONSTRUCTOR                                   9
2199 #define DUK_BIDX_STRING_PROTOTYPE                                     10
2200 #define DUK_BIDX_BOOLEAN_CONSTRUCTOR                                  11
2201 #define DUK_BIDX_BOOLEAN_PROTOTYPE                                    12
2202 #define DUK_BIDX_NUMBER_CONSTRUCTOR                                   13
2203 #define DUK_BIDX_NUMBER_PROTOTYPE                                     14
2204 #define DUK_BIDX_DATE_CONSTRUCTOR                                     15
2205 #define DUK_BIDX_DATE_PROTOTYPE                                       16
2206 #define DUK_BIDX_REGEXP_CONSTRUCTOR                                   17
2207 #define DUK_BIDX_REGEXP_PROTOTYPE                                     18
2208 #define DUK_BIDX_ERROR_CONSTRUCTOR                                    19
2209 #define DUK_BIDX_ERROR_PROTOTYPE                                      20
2210 #define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR                               21
2211 #define DUK_BIDX_EVAL_ERROR_PROTOTYPE                                 22
2212 #define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR                              23
2213 #define DUK_BIDX_RANGE_ERROR_PROTOTYPE                                24
2214 #define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR                          25
2215 #define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE                            26
2216 #define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR                             27
2217 #define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE                               28
2218 #define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR                               29
2219 #define DUK_BIDX_TYPE_ERROR_PROTOTYPE                                 30
2220 #define DUK_BIDX_URI_ERROR_CONSTRUCTOR                                31
2221 #define DUK_BIDX_URI_ERROR_PROTOTYPE                                  32
2222 #define DUK_BIDX_TYPE_ERROR_THROWER                                   33
2223 #define DUK_BIDX_DUKTAPE                                              34
2224 #define DUK_BIDX_THREAD_PROTOTYPE                                     35
2225 #define DUK_BIDX_POINTER_PROTOTYPE                                    36
2226 #define DUK_BIDX_DOUBLE_ERROR                                         37
2227 #define DUK_BIDX_SYMBOL_PROTOTYPE                                     38
2228 #define DUK_BIDX_ARRAYBUFFER_PROTOTYPE                                39
2229 #define DUK_BIDX_DATAVIEW_PROTOTYPE                                   40
2230 #define DUK_BIDX_INT8ARRAY_PROTOTYPE                                  41
2231 #define DUK_BIDX_UINT8ARRAY_PROTOTYPE                                 42
2232 #define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE                          43
2233 #define DUK_BIDX_INT16ARRAY_PROTOTYPE                                 44
2234 #define DUK_BIDX_UINT16ARRAY_PROTOTYPE                                45
2235 #define DUK_BIDX_INT32ARRAY_PROTOTYPE                                 46
2236 #define DUK_BIDX_UINT32ARRAY_PROTOTYPE                                47
2237 #define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE                               48
2238 #define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE                               49
2239 #define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE                              50
2240 #define DUK_NUM_BUILTINS                                              51
2241 #define DUK_NUM_BIDX_BUILTINS                                         51
2242 #define DUK_NUM_ALL_BUILTINS                                          78
2243 #if defined(DUK_USE_DOUBLE_LE)
2244 #if !defined(DUK_SINGLE_FILE)
2245 DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116];
2246 #endif  /* !DUK_SINGLE_FILE */
2247 #define DUK_BUILTINS_DATA_LENGTH                                      4116
2248 #elif defined(DUK_USE_DOUBLE_BE)
2249 #if !defined(DUK_SINGLE_FILE)
2250 DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116];
2251 #endif  /* !DUK_SINGLE_FILE */
2252 #define DUK_BUILTINS_DATA_LENGTH                                      4116
2253 #elif defined(DUK_USE_DOUBLE_ME)
2254 #if !defined(DUK_SINGLE_FILE)
2255 DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[4116];
2256 #endif  /* !DUK_SINGLE_FILE */
2257 #define DUK_BUILTINS_DATA_LENGTH                                      4116
2258 #else
2259 #error invalid endianness defines
2260 #endif
2261 #endif  /* DUK_USE_ROM_OBJECTS */
2262 #endif  /* DUK_BUILTINS_H_INCLUDED */
2263 #line 51 "duk_internal.h"
2264
2265 /* #include duk_util.h */
2266 #line 1 "duk_util.h"
2267 /*
2268  *  Utilities
2269  */
2270
2271 #if !defined(DUK_UTIL_H_INCLUDED)
2272 #define DUK_UTIL_H_INCLUDED
2273
2274 #if defined(DUK_USE_GET_RANDOM_DOUBLE)
2275 #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata)
2276 #else
2277 #define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr)
2278 #endif
2279
2280 /*
2281  *  Some useful constants
2282  */
2283
2284 #define DUK_DOUBLE_2TO32     4294967296.0
2285 #define DUK_DOUBLE_2TO31     2147483648.0
2286 #define DUK_DOUBLE_LOG2E     1.4426950408889634
2287 #define DUK_DOUBLE_LOG10E    0.4342944819032518
2288
2289 /*
2290  *  Endian conversion
2291  */
2292
2293 #if defined(DUK_USE_INTEGER_LE)
2294 #define DUK_HTON32(x) DUK_BSWAP32((x))
2295 #define DUK_NTOH32(x) DUK_BSWAP32((x))
2296 #define DUK_HTON16(x) DUK_BSWAP16((x))
2297 #define DUK_NTOH16(x) DUK_BSWAP16((x))
2298 #elif defined(DUK_USE_INTEGER_BE)
2299 #define DUK_HTON32(x) (x)
2300 #define DUK_NTOH32(x) (x)
2301 #define DUK_HTON16(x) (x)
2302 #define DUK_NTOH16(x) (x)
2303 #else
2304 #error internal error, endianness defines broken
2305 #endif
2306
2307 /*
2308  *  Bitstream decoder
2309  */
2310
2311 struct duk_bitdecoder_ctx {
2312         const duk_uint8_t *data;
2313         duk_size_t offset;
2314         duk_size_t length;
2315         duk_uint32_t currval;
2316         duk_small_int_t currbits;
2317 };
2318
2319 #define DUK_BD_BITPACKED_STRING_MAXLEN 256
2320
2321 /*
2322  *  Bitstream encoder
2323  */
2324
2325 struct duk_bitencoder_ctx {
2326         duk_uint8_t *data;
2327         duk_size_t offset;
2328         duk_size_t length;
2329         duk_uint32_t currval;
2330         duk_small_int_t currbits;
2331         duk_small_int_t truncated;
2332 };
2333
2334 /*
2335  *  Raw write/read macros for big endian, unaligned basic values.
2336  *  Caller ensures there's enough space.  The macros update the pointer
2337  *  argument automatically on resizes.  The idiom seems a bit odd, but
2338  *  leads to compact code.
2339  */
2340
2341 #define DUK_RAW_WRITE_U8(ptr,val)  do { \
2342                 *(ptr)++ = (duk_uint8_t) (val); \
2343         } while (0)
2344 #define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val))
2345 #define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val))
2346 #define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val))
2347 #define DUK_RAW_WRITE_XUTF8(ptr,val)  do { \
2348                 /* 'ptr' is evaluated both as LHS and RHS. */ \
2349                 duk_uint8_t *duk__ptr; \
2350                 duk_small_int_t duk__len; \
2351                 duk__ptr = (duk_uint8_t *) (ptr); \
2352                 duk__len = duk_unicode_encode_xutf8((duk_ucodepoint_t) (val), duk__ptr); \
2353                 duk__ptr += duk__len; \
2354                 (ptr) = duk__ptr; \
2355         } while (0)
2356 #define DUK_RAW_WRITE_CESU8(ptr,val)  do { \
2357                 /* 'ptr' is evaluated both as LHS and RHS. */ \
2358                 duk_uint8_t *duk__ptr; \
2359                 duk_small_int_t duk__len; \
2360                 duk__ptr = (duk_uint8_t *) (ptr); \
2361                 duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \
2362                 duk__ptr += duk__len; \
2363                 (ptr) = duk__ptr; \
2364         } while (0)
2365
2366 #define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++))
2367 #define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr));
2368 #define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr));
2369 #define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr));
2370
2371 /*
2372  *  Buffer writer (dynamic buffer only)
2373  *
2374  *  Helper for writing to a dynamic buffer with a concept of a "slack" area
2375  *  to reduce resizes.  You can ensure there is enough space beforehand and
2376  *  then write for a while without further checks, relying on a stable data
2377  *  pointer.  Slack handling is automatic so call sites only indicate how
2378  *  much data they need right now.
2379  *
2380  *  There are several ways to write using bufwriter.  The best approach
2381  *  depends mainly on how much performance matters over code footprint.
2382  *  The key issues are (1) ensuring there is space and (2) keeping the
2383  *  pointers consistent.  Fast code should ensure space for multiple writes
2384  *  with one ensure call.  Fastest inner loop code can temporarily borrow
2385  *  the 'p' pointer but must write it back eventually.
2386  *
2387  *  Be careful to ensure all macro arguments (other than static pointers like
2388  *  'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if
2389  *  necessary (if that's not possible, there should be a note near the macro).
2390  *  Buffer write arguments often contain arithmetic etc so this is
2391  *  particularly important here.
2392  */
2393
2394 /* XXX: Migrate bufwriter and other read/write helpers to its own header? */
2395
2396 struct duk_bufwriter_ctx {
2397         duk_uint8_t *p;
2398         duk_uint8_t *p_base;
2399         duk_uint8_t *p_limit;
2400         duk_hbuffer_dynamic *buf;
2401 };
2402
2403 #if defined(DUK_USE_PREFER_SIZE)
2404 #define DUK_BW_SLACK_ADD           64
2405 #define DUK_BW_SLACK_SHIFT         4    /* 2^4 -> 1/16 = 6.25% slack */
2406 #else
2407 #define DUK_BW_SLACK_ADD           64
2408 #define DUK_BW_SLACK_SHIFT         2    /* 2^2 -> 1/4 = 25% slack */
2409 #endif
2410
2411 /* Initialization and finalization (compaction), converting to other types. */
2412
2413 #define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \
2414                 duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \
2415         } while (0)
2416 #define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \
2417                 duk_bw_init((thr), (bw_ctx), (buf)); \
2418         } while (0)
2419 #define DUK_BW_COMPACT(thr,bw_ctx) do { \
2420                 /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \
2421                 duk_bw_compact((thr), (bw_ctx)); \
2422         } while (0)
2423 #define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
2424                 duk_push_lstring((thr), \
2425                                  (const char *) (bw_ctx)->p_base, \
2426                                  (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
2427         } while (0)
2428 /* Pointers may be NULL for a while when 'buf' size is zero and before any
2429  * ENSURE calls have been made.  Once an ENSURE has been made, the pointers
2430  * are required to be non-NULL so that it's always valid to use memcpy() and
2431  * memmove(), even for zero size.
2432  */
2433 #define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \
2434         DUK_ASSERT_EXPR((bw_ctx) != NULL && \
2435                         (bw_ctx)->buf != NULL && \
2436                         ((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \
2437                                 ((bw_ctx)->p != NULL && \
2438                                  (bw_ctx)->p_base != NULL && \
2439                                  (bw_ctx)->p_limit != NULL && \
2440                                  (bw_ctx)->p_limit >= (bw_ctx)->p_base && \
2441                                  (bw_ctx)->p >= (bw_ctx)->p_base && \
2442                                  (bw_ctx)->p <= (bw_ctx)->p_limit)))
2443 #define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \
2444                 DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \
2445         } while (0)
2446
2447 /* Working with the pointer and current size. */
2448
2449 #define DUK_BW_GET_PTR(thr,bw_ctx) \
2450         ((bw_ctx)->p)
2451 #define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \
2452                 (bw_ctx)->p = (ptr); \
2453         } while (0)
2454 #define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \
2455                 (bw_ctx)->p += (delta); \
2456         } while (0)
2457 #define DUK_BW_GET_BASEPTR(thr,bw_ctx) \
2458         ((bw_ctx)->p_base)
2459 #define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \
2460         ((bw_ctx)->p_limit)
2461 #define DUK_BW_GET_SIZE(thr,bw_ctx) \
2462         ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base))
2463 #define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \
2464                 DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
2465                 (bw_ctx)->p = (bw_ctx)->p_base + (sz); \
2466         } while (0)
2467 #define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \
2468                 /* Reset to zero size, keep current limit. */ \
2469                 (bw_ctx)->p = (bw_ctx)->p_base; \
2470         } while (0)
2471 #define DUK_BW_GET_BUFFER(thr,bw_ctx) \
2472         ((bw_ctx)->buf)
2473
2474 /* Ensuring (reserving) space. */
2475
2476 #define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \
2477                 duk_size_t duk__sz, duk__space; \
2478                 DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \
2479                 duk__sz = (sz); \
2480                 duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \
2481                 if (duk__space < duk__sz) { \
2482                         (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \
2483                 } \
2484         } while (0)
2485 /* NOTE: Multiple evaluation of 'ptr' in this macro. */
2486 /* XXX: Rework to use an always-inline function? */
2487 #define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \
2488         (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \
2489          (ptr) : \
2490          ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz))))
2491 #define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \
2492         DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p)
2493 #define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \
2494         (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \
2495          DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz)))
2496 #define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \
2497                 DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \
2498         } while (0)
2499
2500 /* Miscellaneous. */
2501
2502 #define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \
2503                 (bw_ctx)->p = (ptr); \
2504                 duk_bw_compact((thr), (bw_ctx)); \
2505         } while (0)
2506
2507 /* Fast write calls which assume you control the slack beforehand.
2508  * Multibyte write variants exist and use a temporary write pointer
2509  * because byte writes alias with anything: with a stored pointer
2510  * explicit pointer load/stores get generated (e.g. gcc -Os).
2511  */
2512
2513 #define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \
2514                 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \
2515                 *(bw_ctx)->p++ = (duk_uint8_t) (val); \
2516         } while (0)
2517 #define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \
2518                 duk_uint8_t *duk__p; \
2519                 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \
2520                 duk__p = (bw_ctx)->p; \
2521                 *duk__p++ = (duk_uint8_t) (val1); \
2522                 *duk__p++ = (duk_uint8_t) (val2); \
2523                 (bw_ctx)->p = duk__p; \
2524         } while (0)
2525 #define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \
2526                 duk_uint8_t *duk__p; \
2527                 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \
2528                 duk__p = (bw_ctx)->p; \
2529                 *duk__p++ = (duk_uint8_t) (val1); \
2530                 *duk__p++ = (duk_uint8_t) (val2); \
2531                 *duk__p++ = (duk_uint8_t) (val3); \
2532                 (bw_ctx)->p = duk__p; \
2533         } while (0)
2534 #define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
2535                 duk_uint8_t *duk__p; \
2536                 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \
2537                 duk__p = (bw_ctx)->p; \
2538                 *duk__p++ = (duk_uint8_t) (val1); \
2539                 *duk__p++ = (duk_uint8_t) (val2); \
2540                 *duk__p++ = (duk_uint8_t) (val3); \
2541                 *duk__p++ = (duk_uint8_t) (val4); \
2542                 (bw_ctx)->p = duk__p; \
2543         } while (0)
2544 #define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
2545                 duk_uint8_t *duk__p; \
2546                 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \
2547                 duk__p = (bw_ctx)->p; \
2548                 *duk__p++ = (duk_uint8_t) (val1); \
2549                 *duk__p++ = (duk_uint8_t) (val2); \
2550                 *duk__p++ = (duk_uint8_t) (val3); \
2551                 *duk__p++ = (duk_uint8_t) (val4); \
2552                 *duk__p++ = (duk_uint8_t) (val5); \
2553                 (bw_ctx)->p = duk__p; \
2554         } while (0)
2555 #define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2556                 duk_uint8_t *duk__p; \
2557                 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \
2558                 duk__p = (bw_ctx)->p; \
2559                 *duk__p++ = (duk_uint8_t) (val1); \
2560                 *duk__p++ = (duk_uint8_t) (val2); \
2561                 *duk__p++ = (duk_uint8_t) (val3); \
2562                 *duk__p++ = (duk_uint8_t) (val4); \
2563                 *duk__p++ = (duk_uint8_t) (val5); \
2564                 *duk__p++ = (duk_uint8_t) (val6); \
2565                 (bw_ctx)->p = duk__p; \
2566         } while (0)
2567 #define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
2568                 duk_ucodepoint_t duk__cp; \
2569                 duk_small_int_t duk__enc_len; \
2570                 duk__cp = (duk_ucodepoint_t) (cp); \
2571                 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
2572                 duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
2573                 (bw_ctx)->p += duk__enc_len; \
2574         } while (0)
2575 #define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \
2576                 duk_ucodepoint_t duk__cp; \
2577                 duk_small_int_t duk__enc_len; \
2578                 duk__cp = (duk_ucodepoint_t) (cp); \
2579                 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \
2580                 duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \
2581                 (bw_ctx)->p += duk__enc_len; \
2582         } while (0)
2583 /* XXX: add temporary duk__p pointer here too; sharing */
2584 /* XXX: avoid unsafe variants */
2585 #define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
2586                 const void *duk__valptr; \
2587                 duk_size_t duk__valsz; \
2588                 duk__valptr = (const void *) (valptr); \
2589                 duk__valsz = (duk_size_t) (valsz); \
2590                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2591                 (bw_ctx)->p += duk__valsz; \
2592         } while (0)
2593 #define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
2594                 const duk_uint8_t *duk__val; \
2595                 duk_size_t duk__val_len; \
2596                 duk__val = (const duk_uint8_t *) (val); \
2597                 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2598                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2599                 (bw_ctx)->p += duk__val_len; \
2600         } while (0)
2601 #define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
2602                 duk_size_t duk__val_len; \
2603                 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2604                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2605                 (bw_ctx)->p += duk__val_len; \
2606         } while (0)
2607 #define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
2608                 duk_size_t duk__val_len; \
2609                 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2610                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2611                 (bw_ctx)->p += duk__val_len; \
2612         } while (0)
2613 #define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2614                 duk_size_t duk__val_len; \
2615                 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2616                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2617                 (bw_ctx)->p += duk__val_len; \
2618         } while (0)
2619 #define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2620                 duk_size_t duk__val_len; \
2621                 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2622                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2623                 (bw_ctx)->p += duk__val_len; \
2624         } while (0)
2625
2626 /* Append bytes from a slice already in the buffer. */
2627 #define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \
2628         duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len))
2629
2630 /* Insert bytes in the middle of the buffer from an external buffer. */
2631 #define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \
2632         duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len))
2633
2634 /* Insert bytes in the middle of the buffer from a slice already
2635  * in the buffer.  Source offset is interpreted "before" the operation.
2636  */
2637 #define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \
2638         duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len))
2639
2640 /* Insert a reserved area somewhere in the buffer; caller fills it.
2641  * Evaluates to a (duk_uint_t *) pointing to the start of the reserved
2642  * area for convenience.
2643  */
2644 #define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \
2645         duk_bw_insert_raw_area((thr), (bw), (off), (len))
2646
2647 /* Remove a slice from inside buffer. */
2648 #define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \
2649         duk_bw_remove_raw_slice((thr), (bw), (off), (len))
2650
2651 /* Safe write calls which will ensure space first. */
2652
2653 #define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \
2654                 DUK_BW_ENSURE((thr), (bw_ctx), 1); \
2655                 DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \
2656         } while (0)
2657 #define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \
2658                 DUK_BW_ENSURE((thr), (bw_ctx), 2); \
2659                 DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \
2660         } while (0)
2661 #define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \
2662                 DUK_BW_ENSURE((thr), (bw_ctx), 3); \
2663                 DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \
2664         } while (0)
2665 #define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
2666                 DUK_BW_ENSURE((thr), (bw_ctx), 4); \
2667                 DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \
2668         } while (0)
2669 #define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
2670                 DUK_BW_ENSURE((thr), (bw_ctx), 5); \
2671                 DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \
2672         } while (0)
2673 #define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2674                 DUK_BW_ENSURE((thr), (bw_ctx), 6); \
2675                 DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \
2676         } while (0)
2677 #define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \
2678                 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \
2679                 DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \
2680         } while (0)
2681 #define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \
2682                 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \
2683                 DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
2684         } while (0)
2685 /* XXX: add temporary duk__p pointer here too; sharing */
2686 /* XXX: avoid unsafe */
2687 #define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \
2688                 const void *duk__valptr; \
2689                 duk_size_t duk__valsz; \
2690                 duk__valptr = (const void *) (valptr); \
2691                 duk__valsz = (duk_size_t) (valsz); \
2692                 DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
2693                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2694                 (bw_ctx)->p += duk__valsz; \
2695         } while (0)
2696 #define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
2697                 const duk_uint8_t *duk__val; \
2698                 duk_size_t duk__val_len; \
2699                 duk__val = (const duk_uint8_t *) (val); \
2700                 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2701                 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2702                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2703                 (bw_ctx)->p += duk__val_len; \
2704         } while (0)
2705 #define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
2706                 duk_size_t duk__val_len; \
2707                 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2708                 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2709                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2710                 (bw_ctx)->p += duk__val_len; \
2711         } while (0)
2712 #define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
2713                 duk_size_t duk__val_len; \
2714                 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2715                 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2716                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2717                 (bw_ctx)->p += duk__val_len; \
2718         } while (0)
2719 #define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2720                 duk_size_t duk__val_len; \
2721                 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2722                 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2723                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2724                 (bw_ctx)->p += duk__val_len; \
2725         } while (0)
2726 #define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2727                 duk_size_t duk__val_len; \
2728                 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2729                 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2730                 duk_memcpy_unsafe((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2731                 (bw_ctx)->p += duk__val_len; \
2732         } while (0)
2733
2734 #define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \
2735         duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len))
2736 #define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \
2737         duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len))
2738 #define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \
2739         duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len))
2740 #define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \
2741         /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \
2742         duk_bw_insert_ensure_area((thr), (bw), (off), (len))
2743 #define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \
2744         /* No difference between raw/ensure because the buffer shrinks. */ \
2745         DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len))
2746
2747 /*
2748  *  Externs and prototypes
2749  */
2750
2751 #if !defined(DUK_SINGLE_FILE)
2752 DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36];
2753 DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16];
2754 DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
2755 #if defined(DUK_USE_HEX_FASTPATH)
2756 DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
2757 DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
2758 #endif
2759 #endif  /* !DUK_SINGLE_FILE */
2760
2761 /* Note: assumes that duk_util_probe_steps size is 32 */
2762 #if defined(DUK_USE_HOBJECT_HASH_PART)
2763 #if !defined(DUK_SINGLE_FILE)
2764 DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
2765 #endif  /* !DUK_SINGLE_FILE */
2766 #endif
2767
2768 #if defined(DUK_USE_STRHASH_DENSE)
2769 DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
2770 #endif
2771
2772 DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
2773 DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
2774 DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value);
2775 DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
2776 DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx);
2777 DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out);
2778
2779 DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
2780 DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
2781
2782 #if !defined(DUK_USE_GET_RANDOM_DOUBLE)
2783 DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
2784 DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr);
2785 #endif
2786
2787 DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
2788 DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
2789 DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz);
2790 DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx);
2791 DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2792 DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2793 DUK_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);
2794 DUK_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);
2795 DUK_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);
2796 DUK_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);
2797 DUK_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);
2798 DUK_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);
2799 DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
2800 /* No duk_bw_remove_ensure_slice(), functionality would be identical. */
2801
2802 DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
2803 DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
2804 DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
2805 DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
2806 DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
2807 DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
2808
2809 #if defined(DUK_USE_DEBUGGER_SUPPORT)  /* For now only needed by the debugger. */
2810 DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
2811 #endif
2812
2813 /* memcpy(), memmove() etc wrappers.  The plain variants like duk_memcpy()
2814  * assume C99+ and 'src' and 'dst' pointers must be non-NULL even when the
2815  * operation size is zero.  The unsafe variants like duk_memcpy_safe() deal
2816  * with the zero size case explicitly, and allow NULL pointers in that case
2817  * (which is undefined behavior in C99+).  For the majority of actual targets
2818  * a NULL pointer with a zero length is fine in practice.  These wrappers are
2819  * macros to force inlining; because there are hundreds of call sites, even a
2820  * few extra bytes per call site adds up to ~1kB footprint.
2821  */
2822 #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
2823 #define duk_memcpy(dst,src,len)  do { \
2824                 void *duk__dst = (dst); \
2825                 const void *duk__src = (src); \
2826                 duk_size_t duk__len = (len); \
2827                 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2828                 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
2829                 (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
2830         } while (0)
2831 #define duk_memcpy_unsafe(dst,src,len)  duk_memcpy((dst), (src), (len))
2832 #define duk_memmove(dst,src,len)  do { \
2833                 void *duk__dst = (dst); \
2834                 const void *duk__src = (src); \
2835                 duk_size_t duk__len = (len); \
2836                 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2837                 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
2838                 (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
2839         } while (0)
2840 #define duk_memmove_unsafe(dst,src,len)  duk_memmove((dst), (src), (len))
2841 #define duk_memset(dst,val,len)  do { \
2842                 void *duk__dst = (dst); \
2843                 duk_small_int_t duk__val = (val); \
2844                 duk_size_t duk__len = (len); \
2845                 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2846                 (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
2847         } while (0)
2848 #define duk_memset_unsafe(dst,val,len)  duk_memset((dst), (val), (len))
2849 #define duk_memzero(dst,len)  do { \
2850                 void *duk__dst = (dst); \
2851                 duk_size_t duk__len = (len); \
2852                 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2853                 (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
2854         } while (0)
2855 #define duk_memzero_unsafe(dst,len)  duk_memzero((dst), (len))
2856 #else  /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
2857 #define duk_memcpy(dst,src,len)  do { \
2858                 void *duk__dst = (dst); \
2859                 const void *duk__src = (src); \
2860                 duk_size_t duk__len = (len); \
2861                 DUK_ASSERT(duk__dst != NULL); \
2862                 DUK_ASSERT(duk__src != NULL); \
2863                 (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
2864         } while (0)
2865 #define duk_memcpy_unsafe(dst,src,len)  do { \
2866                 void *duk__dst = (dst); \
2867                 const void *duk__src = (src); \
2868                 duk_size_t duk__len = (len); \
2869                 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2870                 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
2871                 if (DUK_LIKELY(duk__len > 0U)) { \
2872                         DUK_ASSERT(duk__dst != NULL); \
2873                         DUK_ASSERT(duk__src != NULL); \
2874                         (void) DUK_MEMCPY(duk__dst, duk__src, (size_t) duk__len); \
2875                 } \
2876         } while (0)
2877 #define duk_memmove(dst,src,len)  do { \
2878                 void *duk__dst = (dst); \
2879                 const void *duk__src = (src); \
2880                 duk_size_t duk__len = (len); \
2881                 DUK_ASSERT(duk__dst != NULL); \
2882                 DUK_ASSERT(duk__src != NULL); \
2883                 (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
2884         } while (0)
2885 #define duk_memmove_unsafe(dst,src,len)  do { \
2886                 void *duk__dst = (dst); \
2887                 const void *duk__src = (src); \
2888                 duk_size_t duk__len = (len); \
2889                 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2890                 DUK_ASSERT(duk__src != NULL || duk__len == 0U); \
2891                 if (DUK_LIKELY(duk__len > 0U)) { \
2892                         DUK_ASSERT(duk__dst != NULL); \
2893                         DUK_ASSERT(duk__src != NULL); \
2894                         (void) DUK_MEMMOVE(duk__dst, duk__src, (size_t) duk__len); \
2895                 } \
2896         } while (0)
2897 #define duk_memset(dst,val,len)  do { \
2898                 void *duk__dst = (dst); \
2899                 duk_small_int_t duk__val = (val); \
2900                 duk_size_t duk__len = (len); \
2901                 DUK_ASSERT(duk__dst != NULL); \
2902                 (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
2903         } while (0)
2904 #define duk_memset_unsafe(dst,val,len)  do { \
2905                 void *duk__dst = (dst); \
2906                 duk_small_int_t duk__val = (val); \
2907                 duk_size_t duk__len = (len); \
2908                 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2909                 if (DUK_LIKELY(duk__len > 0U)) { \
2910                         DUK_ASSERT(duk__dst != NULL); \
2911                         (void) DUK_MEMSET(duk__dst, duk__val, (size_t) duk__len); \
2912                 } \
2913         } while (0)
2914 #define duk_memzero(dst,len)  do { \
2915                 void *duk__dst = (dst); \
2916                 duk_size_t duk__len = (len); \
2917                 DUK_ASSERT(duk__dst != NULL); \
2918                 (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
2919         } while (0)
2920 #define duk_memzero_unsafe(dst,len)  do { \
2921                 void *duk__dst = (dst); \
2922                 duk_size_t duk__len = (len); \
2923                 DUK_ASSERT(duk__dst != NULL || duk__len == 0U); \
2924                 if (DUK_LIKELY(duk__len > 0U)) { \
2925                         DUK_ASSERT(duk__dst != NULL); \
2926                         (void) DUK_MEMZERO(duk__dst, (size_t) duk__len); \
2927                 } \
2928         } while (0)
2929 #endif  /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
2930
2931 DUK_INTERNAL_DECL duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len);
2932 DUK_INTERNAL_DECL duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len);
2933
2934 DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival);
2935 DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
2936 DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x);
2937 DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x);
2938 DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x);
2939 DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x);
2940 DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x);
2941 DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x);
2942 DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x);
2943 DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x);
2944 DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x);
2945 DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y);
2946 DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y);
2947 DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
2948 DUK_INTERNAL_DECL duk_bool_t duk_double_is_finite(duk_double_t x);
2949 DUK_INTERNAL_DECL duk_bool_t duk_double_is_integer(duk_double_t x);
2950 DUK_INTERNAL_DECL duk_bool_t duk_double_is_safe_integer(duk_double_t x);
2951
2952 DUK_INTERNAL_DECL duk_double_t duk_double_div(duk_double_t x, duk_double_t y);
2953 DUK_INTERNAL_DECL duk_int_t duk_double_to_int_t(duk_double_t x);
2954 DUK_INTERNAL_DECL duk_uint_t duk_double_to_uint_t(duk_double_t x);
2955 DUK_INTERNAL_DECL duk_int32_t duk_double_to_int32_t(duk_double_t x);
2956 DUK_INTERNAL_DECL duk_uint32_t duk_double_to_uint32_t(duk_double_t x);
2957 DUK_INTERNAL_DECL duk_float_t duk_double_to_float_t(duk_double_t x);
2958
2959 /*
2960  *  Miscellaneous
2961  */
2962
2963 /* Example: x     = 0x10 = 0b00010000
2964  *          x - 1 = 0x0f = 0b00001111
2965  *          x & (x - 1) == 0
2966  *
2967  *          x     = 0x07 = 0b00000111
2968  *          x - 1 = 0x06 = 0b00000110
2969  *          x & (x - 1) != 0
2970  *
2971  * However, incorrectly true for x == 0 so check for that explicitly.
2972  */
2973 #define DUK_IS_POWER_OF_TWO(x) \
2974         ((x) != 0U && ((x) & ((x) - 1U)) == 0U)
2975
2976 #endif  /* DUK_UTIL_H_INCLUDED */
2977 /* #include duk_strings.h */
2978 #line 1 "duk_strings.h"
2979 /*
2980  *  Shared string macros.
2981  *
2982  *  Using shared macros helps minimize strings data size because it's easy
2983  *  to check if an existing string could be used.  String constants don't
2984  *  need to be all defined here; defining a string here makes sense if there's
2985  *  a high chance the string could be reused.  Also, using macros allows
2986  *  a call site express the exact string needed, but the macro may map to an
2987  *  approximate string to reduce unique string count.  Macros can also be
2988  *  more easily tuned for low memory targets than #if defined()s throughout
2989  *  the code base.
2990  *
2991  *  Because format strings behave differently in the call site (they need to
2992  *  be followed by format arguments), they use a special prefix DUK_STR_FMT_.
2993  *
2994  *  On some compilers using explicit shared strings is preferable; on others
2995  *  it may be better to use straight literals because the compiler will combine
2996  *  them anyway, and such strings won't end up unnecessarily in a symbol table.
2997  */
2998
2999 #if !defined(DUK_ERRMSG_H_INCLUDED)
3000 #define DUK_ERRMSG_H_INCLUDED
3001
3002 /* Mostly API and built-in method related */
3003 #define DUK_STR_INTERNAL_ERROR                   "internal error"
3004 #define DUK_STR_UNSUPPORTED                      "unsupported"
3005 #define DUK_STR_INVALID_COUNT                    "invalid count"
3006 #define DUK_STR_INVALID_ARGS                     "invalid args"
3007 #define DUK_STR_INVALID_STATE                    "invalid state"
3008 #define DUK_STR_INVALID_INPUT                    "invalid input"
3009 #define DUK_STR_INVALID_LENGTH                   "invalid length"
3010 #define DUK_STR_NOT_CONSTRUCTABLE                "not constructable"
3011 #define DUK_STR_CONSTRUCT_ONLY                   "constructor requires 'new'"
3012 #define DUK_STR_NOT_CALLABLE                     "not callable"
3013 #define DUK_STR_NOT_EXTENSIBLE                   "not extensible"
3014 #define DUK_STR_NOT_WRITABLE                     "not writable"
3015 #define DUK_STR_NOT_CONFIGURABLE                 "not configurable"
3016 #define DUK_STR_INVALID_CONTEXT                  "invalid context"
3017 #define DUK_STR_INVALID_INDEX                    "invalid args"
3018 #define DUK_STR_PUSH_BEYOND_ALLOC_STACK          "cannot push beyond allocated stack"
3019 #define DUK_STR_NOT_UNDEFINED                    "unexpected type"
3020 #define DUK_STR_NOT_NULL                         "unexpected type"
3021 #define DUK_STR_NOT_BOOLEAN                      "unexpected type"
3022 #define DUK_STR_NOT_NUMBER                       "unexpected type"
3023 #define DUK_STR_NOT_STRING                       "unexpected type"
3024 #define DUK_STR_NOT_OBJECT                       "unexpected type"
3025 #define DUK_STR_NOT_POINTER                      "unexpected type"
3026 #define DUK_STR_NOT_BUFFER                       "not buffer"  /* still in use with verbose messages */
3027 #define DUK_STR_UNEXPECTED_TYPE                  "unexpected type"
3028 #define DUK_STR_NOT_THREAD                       "unexpected type"
3029 #define DUK_STR_NOT_COMPFUNC                     "unexpected type"
3030 #define DUK_STR_NOT_NATFUNC                      "unexpected type"
3031 #define DUK_STR_NOT_C_FUNCTION                   "unexpected type"
3032 #define DUK_STR_NOT_FUNCTION                     "unexpected type"
3033 #define DUK_STR_NOT_REGEXP                       "unexpected type"
3034 #define DUK_STR_TOPRIMITIVE_FAILED               "coercion to primitive failed"
3035 #define DUK_STR_NUMBER_OUTSIDE_RANGE             "number outside range"
3036 #define DUK_STR_NOT_OBJECT_COERCIBLE             "not object coercible"
3037 #define DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL      "cannot number coerce Symbol"
3038 #define DUK_STR_CANNOT_STRING_COERCE_SYMBOL      "cannot string coerce Symbol"
3039 #define DUK_STR_STRING_TOO_LONG                  "string too long"
3040 #define DUK_STR_BUFFER_TOO_LONG                  "buffer too long"
3041 #define DUK_STR_ALLOC_FAILED                     "alloc failed"
3042 #define DUK_STR_WRONG_BUFFER_TYPE                "wrong buffer type"
3043 #define DUK_STR_BASE64_ENCODE_FAILED             "base64 encode failed"
3044 #define DUK_STR_SOURCE_DECODE_FAILED             "source decode failed"
3045 #define DUK_STR_UTF8_DECODE_FAILED               "utf-8 decode failed"
3046 #define DUK_STR_BASE64_DECODE_FAILED             "base64 decode failed"
3047 #define DUK_STR_HEX_DECODE_FAILED                "hex decode failed"
3048 #define DUK_STR_INVALID_BYTECODE                 "invalid bytecode"
3049 #define DUK_STR_NO_SOURCECODE                    "no sourcecode"
3050 #define DUK_STR_RESULT_TOO_LONG                  "result too long"
3051 #define DUK_STR_INVALID_CFUNC_RC                 "invalid C function rc"
3052 #define DUK_STR_INVALID_INSTANCEOF_RVAL          "invalid instanceof rval"
3053 #define DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO  "instanceof rval has no .prototype"
3054
3055 /* JSON */
3056 #define DUK_STR_FMT_PTR                          "%p"
3057 #define DUK_STR_FMT_INVALID_JSON                 "invalid json (at offset %ld)"
3058 #define DUK_STR_JSONDEC_RECLIMIT                 "json decode recursion limit"
3059 #define DUK_STR_JSONENC_RECLIMIT                 "json encode recursion limit"
3060 #define DUK_STR_CYCLIC_INPUT                     "cyclic input"
3061
3062 /* Object property access */
3063 #define DUK_STR_INVALID_BASE                     "invalid base value"
3064 #define DUK_STR_STRICT_CALLER_READ               "cannot read strict 'caller'"
3065 #define DUK_STR_PROXY_REJECTED                   "proxy rejected"
3066 #define DUK_STR_INVALID_ARRAY_LENGTH             "invalid array length"
3067 #define DUK_STR_SETTER_UNDEFINED                 "setter undefined"
3068 #define DUK_STR_INVALID_DESCRIPTOR               "invalid descriptor"
3069
3070 /* Proxy */
3071 #define DUK_STR_PROXY_REVOKED                    "proxy revoked"
3072 #define DUK_STR_INVALID_TRAP_RESULT              "invalid trap result"
3073
3074 /* Variables */
3075
3076 /* Lexer */
3077 #define DUK_STR_INVALID_ESCAPE                   "invalid escape"
3078 #define DUK_STR_UNTERMINATED_STRING              "unterminated string"
3079 #define DUK_STR_UNTERMINATED_COMMENT             "unterminated comment"
3080 #define DUK_STR_UNTERMINATED_REGEXP              "unterminated regexp"
3081 #define DUK_STR_TOKEN_LIMIT                      "token limit"
3082 #define DUK_STR_REGEXP_SUPPORT_DISABLED          "regexp support disabled"
3083 #define DUK_STR_INVALID_NUMBER_LITERAL           "invalid number literal"
3084 #define DUK_STR_INVALID_TOKEN                    "invalid token"
3085
3086 /* Compiler */
3087 #define DUK_STR_PARSE_ERROR                      "parse error"
3088 #define DUK_STR_DUPLICATE_LABEL                  "duplicate label"
3089 #define DUK_STR_INVALID_LABEL                    "invalid label"
3090 #define DUK_STR_INVALID_ARRAY_LITERAL            "invalid array literal"
3091 #define DUK_STR_INVALID_OBJECT_LITERAL           "invalid object literal"
3092 #define DUK_STR_INVALID_VAR_DECLARATION          "invalid variable declaration"
3093 #define DUK_STR_CANNOT_DELETE_IDENTIFIER         "cannot delete identifier"
3094 #define DUK_STR_INVALID_EXPRESSION               "invalid expression"
3095 #define DUK_STR_INVALID_LVALUE                   "invalid lvalue"
3096 #define DUK_STR_INVALID_NEWTARGET                "invalid new.target"
3097 #define DUK_STR_EXPECTED_IDENTIFIER              "expected identifier"
3098 #define DUK_STR_EMPTY_EXPR_NOT_ALLOWED           "empty expression not allowed"
3099 #define DUK_STR_INVALID_FOR                      "invalid for statement"
3100 #define DUK_STR_INVALID_SWITCH                   "invalid switch statement"
3101 #define DUK_STR_INVALID_BREAK_CONT_LABEL         "invalid break/continue label"
3102 #define DUK_STR_INVALID_RETURN                   "invalid return"
3103 #define DUK_STR_INVALID_TRY                      "invalid try"
3104 #define DUK_STR_INVALID_THROW                    "invalid throw"
3105 #define DUK_STR_WITH_IN_STRICT_MODE              "with in strict mode"
3106 #define DUK_STR_FUNC_STMT_NOT_ALLOWED            "function statement not allowed"
3107 #define DUK_STR_UNTERMINATED_STMT                "unterminated statement"
3108 #define DUK_STR_INVALID_ARG_NAME                 "invalid argument name"
3109 #define DUK_STR_INVALID_FUNC_NAME                "invalid function name"
3110 #define DUK_STR_INVALID_GETSET_NAME              "invalid getter/setter name"
3111 #define DUK_STR_FUNC_NAME_REQUIRED               "function name required"
3112
3113 /* RegExp */
3114 #define DUK_STR_INVALID_QUANTIFIER               "invalid regexp quantifier"
3115 #define DUK_STR_INVALID_QUANTIFIER_NO_ATOM       "quantifier without preceding atom"
3116 #define DUK_STR_INVALID_QUANTIFIER_VALUES        "quantifier values invalid (qmin > qmax)"
3117 #define DUK_STR_QUANTIFIER_TOO_MANY_COPIES       "quantifier requires too many atom copies"
3118 #define DUK_STR_UNEXPECTED_CLOSING_PAREN         "unexpected closing parenthesis"
3119 #define DUK_STR_UNEXPECTED_END_OF_PATTERN        "unexpected end of pattern"
3120 #define DUK_STR_UNEXPECTED_REGEXP_TOKEN          "unexpected token in regexp"
3121 #define DUK_STR_INVALID_REGEXP_FLAGS             "invalid regexp flags"
3122 #define DUK_STR_INVALID_REGEXP_ESCAPE            "invalid regexp escape"
3123 #define DUK_STR_INVALID_BACKREFS                 "invalid backreference(s)"
3124 #define DUK_STR_INVALID_REGEXP_CHARACTER         "invalid regexp character"
3125 #define DUK_STR_INVALID_REGEXP_GROUP             "invalid regexp group"
3126 #define DUK_STR_UNTERMINATED_CHARCLASS           "unterminated character class"
3127 #define DUK_STR_INVALID_RANGE                    "invalid range"
3128
3129 /* Limits */
3130 #define DUK_STR_VALSTACK_LIMIT                   "valstack limit"
3131 #define DUK_STR_CALLSTACK_LIMIT                  "callstack limit"
3132 #define DUK_STR_PROTOTYPE_CHAIN_LIMIT            "prototype chain limit"
3133 #define DUK_STR_BOUND_CHAIN_LIMIT                "function call bound chain limit"
3134 #define DUK_STR_C_CALLSTACK_LIMIT                "C call stack depth limit"
3135 #define DUK_STR_COMPILER_RECURSION_LIMIT         "compiler recursion limit"
3136 #define DUK_STR_BYTECODE_LIMIT                   "bytecode limit"
3137 #define DUK_STR_REG_LIMIT                        "register limit"
3138 #define DUK_STR_TEMP_LIMIT                       "temp limit"
3139 #define DUK_STR_CONST_LIMIT                      "const limit"
3140 #define DUK_STR_FUNC_LIMIT                       "function limit"
3141 #define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT  "regexp compiler recursion limit"
3142 #define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT  "regexp executor recursion limit"
3143 #define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT       "regexp step limit"
3144
3145 #endif  /* DUK_ERRMSG_H_INCLUDED */
3146 /* #include duk_js_bytecode.h */
3147 #line 1 "duk_js_bytecode.h"
3148 /*
3149  *  ECMAScript bytecode
3150  */
3151
3152 #if !defined(DUK_JS_BYTECODE_H_INCLUDED)
3153 #define DUK_JS_BYTECODE_H_INCLUDED
3154
3155 /*
3156  *  Bytecode instruction layout
3157  *  ===========================
3158  *
3159  *  Instructions are unsigned 32-bit integers divided as follows:
3160  *
3161  *  !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
3162  *  !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!
3163  *  +-----------------------------------------------+---------------+
3164  *  !       C       !       B       !       A       !       OP      !
3165  *  +-----------------------------------------------+---------------+
3166  *
3167  *  OP (8 bits):  opcode (DUK_OP_*), access should be fastest
3168  *                consecutive opcodes allocated when opcode needs flags
3169  *   A (8 bits):  typically a target register number
3170  *   B (8 bits):  typically first source register/constant number
3171  *   C (8 bits):  typically second source register/constant number
3172  *
3173  *  Some instructions combine BC or ABC together for larger parameter values.
3174  *  Signed integers (e.g. jump offsets) are encoded as unsigned, with an
3175  *  opcode specific bias.
3176  *
3177  *  Some opcodes have flags which are handled by allocating consecutive
3178  *  opcodes to make space for 1-N flags.  Flags can also be e.g. in the 'A'
3179  *  field when there's room for the specific opcode.
3180  *
3181  *  For example, if three flags were needed, they could be allocated from
3182  *  the opcode field as follows:
3183  *
3184  *  !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
3185  *  !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!
3186  *  +-----------------------------------------------+---------------+
3187  *  !       C       !       B       !       A       !    OP   !Z!Y!X!
3188  *  +-----------------------------------------------+---------------+
3189  *
3190  *  Some opcodes accept a reg/const argument which is handled by allocating
3191  *  flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST().  The
3192  *  following convention is shared by most opcodes, so that the compiler
3193  *  can handle reg/const flagging without opcode specific code paths:
3194  *
3195  *  !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
3196  *  !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!
3197  *  +-----------------------------------------------+---------------+
3198  *  !       C       !       B       !       A       !     OP    !Y!X!
3199  *  +-----------------------------------------------+---------------+
3200  *
3201  *    X  1=B is const, 0=B is reg
3202  *    Y  1=C is const, 0=C is reg
3203  *
3204  *    In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the
3205  *    8-bit opcode space for a single logical opcode.  The base opcode
3206  *    number should be divisible by 4.  If the opcode is called 'FOO'
3207  *    the following opcode constants would be defined:
3208  *
3209  *      DUK_OP_FOO     100       // base opcode number
3210  *      DUK_OP_FOO_RR  100       // FOO, B=reg, C=reg
3211  *      DUK_OP_FOO_CR  101       // FOO, B=const, C=reg
3212  *      DUK_OP_FOO_RC  102       // FOO, B=reg, C=const
3213  *      DUK_OP_FOO_CC  103       // FOO, B=const, C=const
3214  *
3215  *  If only B or C is a reg/const, the unused opcode combinations can be
3216  *  used for other opcodes (which take no reg/const argument).  However,
3217  *  such opcode values are initially reserved, at least while opcode space
3218  *  is available.  For example, if 'BAR' uses B for a register field and
3219  *  C is a reg/const:
3220  *
3221  *      DUK_OP_BAR            116    // base opcode number
3222  *      DUK_OP_BAR_RR         116    // BAR, B=reg, C=reg
3223  *      DUK_OP_BAR_CR_UNUSED  117    // unused, could be repurposed
3224  *      DUK_OP_BAR_RC         118    // BAR, B=reg, C=const
3225  *      DUK_OP_BAR_CC_UNUSED  119    // unused, could be repurposed
3226  *
3227  *  Macro naming is a bit misleading, e.g. "ABC" in macro name but the
3228  *  field layout is concretely "CBA" in the register.
3229  */
3230
3231 typedef duk_uint32_t duk_instr_t;
3232
3233 #define DUK_BC_SHIFT_OP             0
3234 #define DUK_BC_SHIFT_A              8
3235 #define DUK_BC_SHIFT_B              16
3236 #define DUK_BC_SHIFT_C              24
3237 #define DUK_BC_SHIFT_BC             DUK_BC_SHIFT_B
3238 #define DUK_BC_SHIFT_ABC            DUK_BC_SHIFT_A
3239
3240 #define DUK_BC_UNSHIFTED_MASK_OP    0xffUL
3241 #define DUK_BC_UNSHIFTED_MASK_A     0xffUL
3242 #define DUK_BC_UNSHIFTED_MASK_B     0xffUL
3243 #define DUK_BC_UNSHIFTED_MASK_C     0xffUL
3244 #define DUK_BC_UNSHIFTED_MASK_BC    0xffffUL
3245 #define DUK_BC_UNSHIFTED_MASK_ABC   0xffffffUL
3246
3247 #define DUK_BC_SHIFTED_MASK_OP      (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP)
3248 #define DUK_BC_SHIFTED_MASK_A       (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A)
3249 #define DUK_BC_SHIFTED_MASK_B       (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B)
3250 #define DUK_BC_SHIFTED_MASK_C       (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C)
3251 #define DUK_BC_SHIFTED_MASK_BC      (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC)
3252 #define DUK_BC_SHIFTED_MASK_ABC     (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC)
3253
3254 #define DUK_DEC_OP(x)               ((x) & 0xffUL)
3255 #define DUK_DEC_A(x)                (((x) >> 8) & 0xffUL)
3256 #define DUK_DEC_B(x)                (((x) >> 16) & 0xffUL)
3257 #define DUK_DEC_C(x)                (((x) >> 24) & 0xffUL)
3258 #define DUK_DEC_BC(x)               (((x) >> 16) & 0xffffUL)
3259 #define DUK_DEC_ABC(x)              (((x) >> 8) & 0xffffffUL)
3260
3261 #define DUK_ENC_OP(op)              ((duk_instr_t) (op))
3262 #define DUK_ENC_OP_ABC(op,abc)      ((duk_instr_t) ( \
3263                                         (((duk_instr_t) (abc)) << 8) | \
3264                                         ((duk_instr_t) (op)) \
3265                                     ))
3266 #define DUK_ENC_OP_A_BC(op,a,bc)    ((duk_instr_t) ( \
3267                                         (((duk_instr_t) (bc)) << 16) | \
3268                                         (((duk_instr_t) (a)) << 8) | \
3269                                         ((duk_instr_t) (op)) \
3270                                     ))
3271 #define DUK_ENC_OP_A_B_C(op,a,b,c)  ((duk_instr_t) ( \
3272                                         (((duk_instr_t) (c)) << 24) | \
3273                                         (((duk_instr_t) (b)) << 16) | \
3274                                         (((duk_instr_t) (a)) << 8) | \
3275                                         ((duk_instr_t) (op)) \
3276                                     ))
3277 #define DUK_ENC_OP_A_B(op,a,b)      DUK_ENC_OP_A_B_C((op),(a),(b),0)
3278 #define DUK_ENC_OP_A(op,a)          DUK_ENC_OP_A_B_C((op),(a),0,0)
3279 #define DUK_ENC_OP_BC(op,bc)        DUK_ENC_OP_A_BC((op),0,(bc))
3280
3281 /* Get opcode base value with B/C reg/const flags cleared. */
3282 #define DUK_BC_NOREGCONST_OP(op)    ((op) & 0xfc)
3283
3284 /* Constants should be signed so that signed arithmetic involving them
3285  * won't cause values to be coerced accidentally to unsigned.
3286  */
3287 #define DUK_BC_OP_MIN               0
3288 #define DUK_BC_OP_MAX               0xffL
3289 #define DUK_BC_A_MIN                0
3290 #define DUK_BC_A_MAX                0xffL
3291 #define DUK_BC_B_MIN                0
3292 #define DUK_BC_B_MAX                0xffL
3293 #define DUK_BC_C_MIN                0
3294 #define DUK_BC_C_MAX                0xffL
3295 #define DUK_BC_BC_MIN               0
3296 #define DUK_BC_BC_MAX               0xffffL
3297 #define DUK_BC_ABC_MIN              0
3298 #define DUK_BC_ABC_MAX              0xffffffL
3299
3300 /* Masks for B/C reg/const indicator in opcode field. */
3301 #define DUK_BC_REGCONST_B           (0x01UL)
3302 #define DUK_BC_REGCONST_C           (0x02UL)
3303
3304 /* Misc. masks for opcode field. */
3305 #define DUK_BC_INCDECP_FLAG_DEC     (0x04UL)
3306 #define DUK_BC_INCDECP_FLAG_POST    (0x08UL)
3307
3308 /* Opcodes. */
3309 #define DUK_OP_LDREG                0
3310 #define DUK_OP_STREG                1
3311 #define DUK_OP_JUMP                 2
3312 #define DUK_OP_LDCONST              3
3313 #define DUK_OP_LDINT                4
3314 #define DUK_OP_LDINTX               5
3315 #define DUK_OP_LDTHIS               6
3316 #define DUK_OP_LDUNDEF              7
3317 #define DUK_OP_LDNULL               8
3318 #define DUK_OP_LDTRUE               9
3319 #define DUK_OP_LDFALSE              10
3320 #define DUK_OP_GETVAR               11
3321 #define DUK_OP_BNOT                 12
3322 #define DUK_OP_LNOT                 13
3323 #define DUK_OP_UNM                  14
3324 #define DUK_OP_UNP                  15
3325 #define DUK_OP_EQ                   16
3326 #define DUK_OP_EQ_RR                16
3327 #define DUK_OP_EQ_CR                17
3328 #define DUK_OP_EQ_RC                18
3329 #define DUK_OP_EQ_CC                19
3330 #define DUK_OP_NEQ                  20
3331 #define DUK_OP_NEQ_RR               20
3332 #define DUK_OP_NEQ_CR               21
3333 #define DUK_OP_NEQ_RC               22
3334 #define DUK_OP_NEQ_CC               23
3335 #define DUK_OP_SEQ                  24
3336 #define DUK_OP_SEQ_RR               24
3337 #define DUK_OP_SEQ_CR               25
3338 #define DUK_OP_SEQ_RC               26
3339 #define DUK_OP_SEQ_CC               27
3340 #define DUK_OP_SNEQ                 28
3341 #define DUK_OP_SNEQ_RR              28
3342 #define DUK_OP_SNEQ_CR              29
3343 #define DUK_OP_SNEQ_RC              30
3344 #define DUK_OP_SNEQ_CC              31
3345 #define DUK_OP_GT                   32
3346 #define DUK_OP_GT_RR                32
3347 #define DUK_OP_GT_CR                33
3348 #define DUK_OP_GT_RC                34
3349 #define DUK_OP_GT_CC                35
3350 #define DUK_OP_GE                   36
3351 #define DUK_OP_GE_RR                36
3352 #define DUK_OP_GE_CR                37
3353 #define DUK_OP_GE_RC                38
3354 #define DUK_OP_GE_CC                39
3355 #define DUK_OP_LT                   40
3356 #define DUK_OP_LT_RR                40
3357 #define DUK_OP_LT_CR                41
3358 #define DUK_OP_LT_RC                42
3359 #define DUK_OP_LT_CC                43
3360 #define DUK_OP_LE                   44
3361 #define DUK_OP_LE_RR                44
3362 #define DUK_OP_LE_CR                45
3363 #define DUK_OP_LE_RC                46
3364 #define DUK_OP_LE_CC                47
3365 #define DUK_OP_IFTRUE               48
3366 #define DUK_OP_IFTRUE_R             48
3367 #define DUK_OP_IFTRUE_C             49
3368 #define DUK_OP_IFFALSE              50
3369 #define DUK_OP_IFFALSE_R            50
3370 #define DUK_OP_IFFALSE_C            51
3371 #define DUK_OP_ADD                  52
3372 #define DUK_OP_ADD_RR               52
3373 #define DUK_OP_ADD_CR               53
3374 #define DUK_OP_ADD_RC               54
3375 #define DUK_OP_ADD_CC               55
3376 #define DUK_OP_SUB                  56
3377 #define DUK_OP_SUB_RR               56
3378 #define DUK_OP_SUB_CR               57
3379 #define DUK_OP_SUB_RC               58
3380 #define DUK_OP_SUB_CC               59
3381 #define DUK_OP_MUL                  60
3382 #define DUK_OP_MUL_RR               60
3383 #define DUK_OP_MUL_CR               61
3384 #define DUK_OP_MUL_RC               62
3385 #define DUK_OP_MUL_CC               63
3386 #define DUK_OP_DIV                  64
3387 #define DUK_OP_DIV_RR               64
3388 #define DUK_OP_DIV_CR               65
3389 #define DUK_OP_DIV_RC               66
3390 #define DUK_OP_DIV_CC               67
3391 #define DUK_OP_MOD                  68
3392 #define DUK_OP_MOD_RR               68
3393 #define DUK_OP_MOD_CR               69
3394 #define DUK_OP_MOD_RC               70
3395 #define DUK_OP_MOD_CC               71
3396 #define DUK_OP_EXP                  72
3397 #define DUK_OP_EXP_RR               72
3398 #define DUK_OP_EXP_CR               73
3399 #define DUK_OP_EXP_RC               74
3400 #define DUK_OP_EXP_CC               75
3401 #define DUK_OP_BAND                 76
3402 #define DUK_OP_BAND_RR              76
3403 #define DUK_OP_BAND_CR              77
3404 #define DUK_OP_BAND_RC              78
3405 #define DUK_OP_BAND_CC              79
3406 #define DUK_OP_BOR                  80
3407 #define DUK_OP_BOR_RR               80
3408 #define DUK_OP_BOR_CR               81
3409 #define DUK_OP_BOR_RC               82
3410 #define DUK_OP_BOR_CC               83
3411 #define DUK_OP_BXOR                 84
3412 #define DUK_OP_BXOR_RR              84
3413 #define DUK_OP_BXOR_CR              85
3414 #define DUK_OP_BXOR_RC              86
3415 #define DUK_OP_BXOR_CC              87
3416 #define DUK_OP_BASL                 88
3417 #define DUK_OP_BASL_RR              88
3418 #define DUK_OP_BASL_CR              89
3419 #define DUK_OP_BASL_RC              90
3420 #define DUK_OP_BASL_CC              91
3421 #define DUK_OP_BLSR                 92
3422 #define DUK_OP_BLSR_RR              92
3423 #define DUK_OP_BLSR_CR              93
3424 #define DUK_OP_BLSR_RC              94
3425 #define DUK_OP_BLSR_CC              95
3426 #define DUK_OP_BASR                 96
3427 #define DUK_OP_BASR_RR              96
3428 #define DUK_OP_BASR_CR              97
3429 #define DUK_OP_BASR_RC              98
3430 #define DUK_OP_BASR_CC              99
3431 #define DUK_OP_INSTOF               100
3432 #define DUK_OP_INSTOF_RR            100
3433 #define DUK_OP_INSTOF_CR            101
3434 #define DUK_OP_INSTOF_RC            102
3435 #define DUK_OP_INSTOF_CC            103
3436 #define DUK_OP_IN                   104
3437 #define DUK_OP_IN_RR                104
3438 #define DUK_OP_IN_CR                105
3439 #define DUK_OP_IN_RC                106
3440 #define DUK_OP_IN_CC                107
3441 #define DUK_OP_GETPROP              108
3442 #define DUK_OP_GETPROP_RR           108
3443 #define DUK_OP_GETPROP_CR           109
3444 #define DUK_OP_GETPROP_RC           110
3445 #define DUK_OP_GETPROP_CC           111
3446 #define DUK_OP_PUTPROP              112
3447 #define DUK_OP_PUTPROP_RR           112
3448 #define DUK_OP_PUTPROP_CR           113
3449 #define DUK_OP_PUTPROP_RC           114
3450 #define DUK_OP_PUTPROP_CC           115
3451 #define DUK_OP_DELPROP              116
3452 #define DUK_OP_DELPROP_RR           116
3453 #define DUK_OP_DELPROP_CR_UNUSED    117  /* unused now */
3454 #define DUK_OP_DELPROP_RC           118
3455 #define DUK_OP_DELPROP_CC_UNUSED    119  /* unused now */
3456 #define DUK_OP_PREINCR              120  /* pre/post opcode values have constraints, */
3457 #define DUK_OP_PREDECR              121  /* see duk_js_executor.c and duk_js_compiler.c. */
3458 #define DUK_OP_POSTINCR             122
3459 #define DUK_OP_POSTDECR             123
3460 #define DUK_OP_PREINCV              124
3461 #define DUK_OP_PREDECV              125
3462 #define DUK_OP_POSTINCV             126
3463 #define DUK_OP_POSTDECV             127
3464 #define DUK_OP_PREINCP              128  /* pre/post inc/dec prop opcodes have constraints */
3465 #define DUK_OP_PREINCP_RR           128
3466 #define DUK_OP_PREINCP_CR           129
3467 #define DUK_OP_PREINCP_RC           130
3468 #define DUK_OP_PREINCP_CC           131
3469 #define DUK_OP_PREDECP              132
3470 #define DUK_OP_PREDECP_RR           132
3471 #define DUK_OP_PREDECP_CR           133
3472 #define DUK_OP_PREDECP_RC           134
3473 #define DUK_OP_PREDECP_CC           135
3474 #define DUK_OP_POSTINCP             136
3475 #define DUK_OP_POSTINCP_RR          136
3476 #define DUK_OP_POSTINCP_CR          137
3477 #define DUK_OP_POSTINCP_RC          138
3478 #define DUK_OP_POSTINCP_CC          139
3479 #define DUK_OP_POSTDECP             140
3480 #define DUK_OP_POSTDECP_RR          140
3481 #define DUK_OP_POSTDECP_CR          141
3482 #define DUK_OP_POSTDECP_RC          142
3483 #define DUK_OP_POSTDECP_CC          143
3484 #define DUK_OP_DECLVAR              144
3485 #define DUK_OP_DECLVAR_RR           144
3486 #define DUK_OP_DECLVAR_CR           145
3487 #define DUK_OP_DECLVAR_RC           146
3488 #define DUK_OP_DECLVAR_CC           147
3489 #define DUK_OP_REGEXP               148
3490 #define DUK_OP_REGEXP_RR            148
3491 #define DUK_OP_REGEXP_CR            149
3492 #define DUK_OP_REGEXP_RC            150
3493 #define DUK_OP_REGEXP_CC            151
3494 #define DUK_OP_CLOSURE              152
3495 #define DUK_OP_TYPEOF               153
3496 #define DUK_OP_TYPEOFID             154
3497 #define DUK_OP_PUTVAR               155
3498 #define DUK_OP_DELVAR               156
3499 #define DUK_OP_RETREG               157
3500 #define DUK_OP_RETUNDEF             158
3501 #define DUK_OP_RETCONST             159
3502 #define DUK_OP_RETCONSTN            160  /* return const without incref (e.g. number) */
3503 #define DUK_OP_LABEL                161
3504 #define DUK_OP_ENDLABEL             162
3505 #define DUK_OP_BREAK                163
3506 #define DUK_OP_CONTINUE             164
3507 #define DUK_OP_TRYCATCH             165
3508 #define DUK_OP_ENDTRY               166
3509 #define DUK_OP_ENDCATCH             167
3510 #define DUK_OP_ENDFIN               168
3511 #define DUK_OP_THROW                169
3512 #define DUK_OP_INVLHS               170
3513 #define DUK_OP_CSREG                171
3514 #define DUK_OP_CSVAR                172
3515 #define DUK_OP_CSVAR_RR             172
3516 #define DUK_OP_CSVAR_CR             173
3517 #define DUK_OP_CSVAR_RC             174
3518 #define DUK_OP_CSVAR_CC             175
3519 #define DUK_OP_CALL0                176  /* DUK_OP_CALL0 & 0x0F must be zero. */
3520 #define DUK_OP_CALL1                177
3521 #define DUK_OP_CALL2                178
3522 #define DUK_OP_CALL3                179
3523 #define DUK_OP_CALL4                180
3524 #define DUK_OP_CALL5                181
3525 #define DUK_OP_CALL6                182
3526 #define DUK_OP_CALL7                183
3527 #define DUK_OP_CALL8                184
3528 #define DUK_OP_CALL9                185
3529 #define DUK_OP_CALL10               186
3530 #define DUK_OP_CALL11               187
3531 #define DUK_OP_CALL12               188
3532 #define DUK_OP_CALL13               189
3533 #define DUK_OP_CALL14               190
3534 #define DUK_OP_CALL15               191
3535 #define DUK_OP_NEWOBJ               192
3536 #define DUK_OP_NEWARR               193
3537 #define DUK_OP_MPUTOBJ              194
3538 #define DUK_OP_MPUTOBJI             195
3539 #define DUK_OP_INITSET              196
3540 #define DUK_OP_INITGET              197
3541 #define DUK_OP_MPUTARR              198
3542 #define DUK_OP_MPUTARRI             199
3543 #define DUK_OP_SETALEN              200
3544 #define DUK_OP_INITENUM             201
3545 #define DUK_OP_NEXTENUM             202
3546 #define DUK_OP_NEWTARGET            203
3547 #define DUK_OP_DEBUGGER             204
3548 #define DUK_OP_NOP                  205
3549 #define DUK_OP_INVALID              206
3550 #define DUK_OP_UNUSED207            207
3551 #define DUK_OP_GETPROPC             208
3552 #define DUK_OP_GETPROPC_RR          208
3553 #define DUK_OP_GETPROPC_CR          209
3554 #define DUK_OP_GETPROPC_RC          210
3555 #define DUK_OP_GETPROPC_CC          211
3556 #define DUK_OP_UNUSED212            212
3557 #define DUK_OP_UNUSED213            213
3558 #define DUK_OP_UNUSED214            214
3559 #define DUK_OP_UNUSED215            215
3560 #define DUK_OP_UNUSED216            216
3561 #define DUK_OP_UNUSED217            217
3562 #define DUK_OP_UNUSED218            218
3563 #define DUK_OP_UNUSED219            219
3564 #define DUK_OP_UNUSED220            220
3565 #define DUK_OP_UNUSED221            221
3566 #define DUK_OP_UNUSED222            222
3567 #define DUK_OP_UNUSED223            223
3568 #define DUK_OP_UNUSED224            224
3569 #define DUK_OP_UNUSED225            225
3570 #define DUK_OP_UNUSED226            226
3571 #define DUK_OP_UNUSED227            227
3572 #define DUK_OP_UNUSED228            228
3573 #define DUK_OP_UNUSED229            229
3574 #define DUK_OP_UNUSED230            230
3575 #define DUK_OP_UNUSED231            231
3576 #define DUK_OP_UNUSED232            232
3577 #define DUK_OP_UNUSED233            233
3578 #define DUK_OP_UNUSED234            234
3579 #define DUK_OP_UNUSED235            235
3580 #define DUK_OP_UNUSED236            236
3581 #define DUK_OP_UNUSED237            237
3582 #define DUK_OP_UNUSED238            238
3583 #define DUK_OP_UNUSED239            239
3584 #define DUK_OP_UNUSED240            240
3585 #define DUK_OP_UNUSED241            241
3586 #define DUK_OP_UNUSED242            242
3587 #define DUK_OP_UNUSED243            243
3588 #define DUK_OP_UNUSED244            244
3589 #define DUK_OP_UNUSED245            245
3590 #define DUK_OP_UNUSED246            246
3591 #define DUK_OP_UNUSED247            247
3592 #define DUK_OP_UNUSED248            248
3593 #define DUK_OP_UNUSED249            249
3594 #define DUK_OP_UNUSED250            250
3595 #define DUK_OP_UNUSED251            251
3596 #define DUK_OP_UNUSED252            252
3597 #define DUK_OP_UNUSED253            253
3598 #define DUK_OP_UNUSED254            254
3599 #define DUK_OP_UNUSED255            255
3600 #define DUK_OP_NONE                 256  /* dummy value used as marker (doesn't fit in 8-bit field) */
3601
3602 /* XXX: Allocate flags from opcode field?  Would take 16 opcode slots
3603  * but avoids shuffling in more cases.  Maybe not worth it.
3604  */
3605 /* DUK_OP_TRYCATCH flags in A. */
3606 #define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH     (1U << 0)
3607 #define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY   (1U << 1)
3608 #define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING  (1U << 2)
3609 #define DUK_BC_TRYCATCH_FLAG_WITH_BINDING   (1U << 3)
3610
3611 /* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags
3612  * (DUK_PROPDESC_FLAG_XXX).
3613  */
3614 #define DUK_BC_DECLVAR_FLAG_FUNC_DECL       (1U << 4)  /* function declaration */
3615
3616 /* DUK_OP_CALLn flags, part of opcode field.  Three lowest bits must match
3617  * DUK_CALL_FLAG_xxx directly.
3618  */
3619 #define DUK_BC_CALL_FLAG_TAILCALL           (1U << 0)
3620 #define DUK_BC_CALL_FLAG_CONSTRUCT          (1U << 1)
3621 #define DUK_BC_CALL_FLAG_CALLED_AS_EVAL     (1U << 2)
3622 #define DUK_BC_CALL_FLAG_INDIRECT           (1U << 3)
3623
3624 /* Misc constants and helper macros. */
3625 #define DUK_BC_LDINT_BIAS           (1L << 15)
3626 #define DUK_BC_LDINTX_SHIFT         16
3627 #define DUK_BC_JUMP_BIAS            (1L << 23)
3628
3629 #endif  /* DUK_JS_BYTECODE_H_INCLUDED */
3630 /* #include duk_lexer.h */
3631 #line 1 "duk_lexer.h"
3632 /*
3633  *  Lexer defines.
3634  */
3635
3636 #if !defined(DUK_LEXER_H_INCLUDED)
3637 #define DUK_LEXER_H_INCLUDED
3638
3639 typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct);
3640
3641 /*
3642  *  A token is interpreted as any possible production of InputElementDiv
3643  *  and InputElementRegExp, see E5 Section 7 in its entirety.  Note that
3644  *  the E5 "Token" production does not cover all actual tokens of the
3645  *  language (which is explicitly stated in the specification, Section 7.5).
3646  *  Null and boolean literals are defined as part of both ReservedWord
3647  *  (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions.  Here,
3648  *  null and boolean values have literal tokens, and are not reserved
3649  *  words.
3650  *
3651  *  Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER.
3652  *  The number tokens always have a non-negative value.  The unary minus
3653  *  operator in "-1.0" is optimized during compilation to yield a single
3654  *  negative constant.
3655  *
3656  *  Token numbering is free except that reserved words are required to be
3657  *  in a continuous range and in a particular order.  See genstrings.py.
3658  */
3659
3660 #define DUK_LEXER_INITCTX(ctx)        duk_lexer_initctx((ctx))
3661
3662 #define DUK_LEXER_SETPOINT(ctx,pt)    duk_lexer_setpoint((ctx), (pt))
3663
3664 #define DUK_LEXER_GETPOINT(ctx,pt)    duk_lexer_getpoint((ctx), (pt))
3665
3666 /* Currently 6 characters of lookup are actually needed (duk_lexer.c). */
3667 #define DUK_LEXER_WINDOW_SIZE                     6
3668 #if defined(DUK_USE_LEXER_SLIDING_WINDOW)
3669 #define DUK_LEXER_BUFFER_SIZE                     64
3670 #endif
3671
3672 #define DUK_TOK_MINVAL                            0
3673
3674 /* returned after EOF (infinite amount) */
3675 #define DUK_TOK_EOF                               0
3676
3677 /* identifier names (E5 Section 7.6) */
3678 #define DUK_TOK_IDENTIFIER                        1
3679
3680 /* reserved words: keywords */
3681 #define DUK_TOK_START_RESERVED                    2
3682 #define DUK_TOK_BREAK                             2
3683 #define DUK_TOK_CASE                              3
3684 #define DUK_TOK_CATCH                             4
3685 #define DUK_TOK_CONTINUE                          5
3686 #define DUK_TOK_DEBUGGER                          6
3687 #define DUK_TOK_DEFAULT                           7
3688 #define DUK_TOK_DELETE                            8
3689 #define DUK_TOK_DO                                9
3690 #define DUK_TOK_ELSE                              10
3691 #define DUK_TOK_FINALLY                           11
3692 #define DUK_TOK_FOR                               12
3693 #define DUK_TOK_FUNCTION                          13
3694 #define DUK_TOK_IF                                14
3695 #define DUK_TOK_IN                                15
3696 #define DUK_TOK_INSTANCEOF                        16
3697 #define DUK_TOK_NEW                               17
3698 #define DUK_TOK_RETURN                            18
3699 #define DUK_TOK_SWITCH                            19
3700 #define DUK_TOK_THIS                              20
3701 #define DUK_TOK_THROW                             21
3702 #define DUK_TOK_TRY                               22
3703 #define DUK_TOK_TYPEOF                            23
3704 #define DUK_TOK_VAR                               24
3705 #define DUK_TOK_CONST                             25
3706 #define DUK_TOK_VOID                              26
3707 #define DUK_TOK_WHILE                             27
3708 #define DUK_TOK_WITH                              28
3709
3710 /* reserved words: future reserved words */
3711 #define DUK_TOK_CLASS                             29
3712 #define DUK_TOK_ENUM                              30
3713 #define DUK_TOK_EXPORT                            31
3714 #define DUK_TOK_EXTENDS                           32
3715 #define DUK_TOK_IMPORT                            33
3716 #define DUK_TOK_SUPER                             34
3717
3718 /* "null", "true", and "false" are always reserved words.
3719  * Note that "get" and "set" are not!
3720  */
3721 #define DUK_TOK_NULL                              35
3722 #define DUK_TOK_TRUE                              36
3723 #define DUK_TOK_FALSE                             37
3724
3725 /* reserved words: additional future reserved words in strict mode */
3726 #define DUK_TOK_START_STRICT_RESERVED             38  /* inclusive */
3727 #define DUK_TOK_IMPLEMENTS                        38
3728 #define DUK_TOK_INTERFACE                         39
3729 #define DUK_TOK_LET                               40
3730 #define DUK_TOK_PACKAGE                           41
3731 #define DUK_TOK_PRIVATE                           42
3732 #define DUK_TOK_PROTECTED                         43
3733 #define DUK_TOK_PUBLIC                            44
3734 #define DUK_TOK_STATIC                            45
3735 #define DUK_TOK_YIELD                             46
3736
3737 #define DUK_TOK_END_RESERVED                      47  /* exclusive */
3738
3739 /* "get" and "set" are tokens but NOT ReservedWords.  They are currently
3740  * parsed and identifiers and these defines are actually now unused.
3741  */
3742 #define DUK_TOK_GET                               47
3743 #define DUK_TOK_SET                               48
3744
3745 /* punctuators (unlike the spec, also includes "/" and "/=") */
3746 #define DUK_TOK_LCURLY                            49
3747 #define DUK_TOK_RCURLY                            50
3748 #define DUK_TOK_LBRACKET                          51
3749 #define DUK_TOK_RBRACKET                          52
3750 #define DUK_TOK_LPAREN                            53
3751 #define DUK_TOK_RPAREN                            54
3752 #define DUK_TOK_PERIOD                            55
3753 #define DUK_TOK_SEMICOLON                         56
3754 #define DUK_TOK_COMMA                             57
3755 #define DUK_TOK_LT                                58
3756 #define DUK_TOK_GT                                59
3757 #define DUK_TOK_LE                                60
3758 #define DUK_TOK_GE                                61
3759 #define DUK_TOK_EQ                                62
3760 #define DUK_TOK_NEQ                               63
3761 #define DUK_TOK_SEQ                               64
3762 #define DUK_TOK_SNEQ                              65
3763 #define DUK_TOK_ADD                               66
3764 #define DUK_TOK_SUB                               67
3765 #define DUK_TOK_MUL                               68
3766 #define DUK_TOK_DIV                               69
3767 #define DUK_TOK_MOD                               70
3768 #define DUK_TOK_EXP                               71
3769 #define DUK_TOK_INCREMENT                         72
3770 #define DUK_TOK_DECREMENT                         73
3771 #define DUK_TOK_ALSHIFT                           74   /* named "arithmetic" because result is signed */
3772 #define DUK_TOK_ARSHIFT                           75
3773 #define DUK_TOK_RSHIFT                            76
3774 #define DUK_TOK_BAND                              77
3775 #define DUK_TOK_BOR                               78
3776 #define DUK_TOK_BXOR                              79
3777 #define DUK_TOK_LNOT                              80
3778 #define DUK_TOK_BNOT                              81
3779 #define DUK_TOK_LAND                              82
3780 #define DUK_TOK_LOR                               83
3781 #define DUK_TOK_QUESTION                          84
3782 #define DUK_TOK_COLON                             85
3783 #define DUK_TOK_EQUALSIGN                         86
3784 #define DUK_TOK_ADD_EQ                            87
3785 #define DUK_TOK_SUB_EQ                            88
3786 #define DUK_TOK_MUL_EQ                            89
3787 #define DUK_TOK_DIV_EQ                            90
3788 #define DUK_TOK_MOD_EQ                            91
3789 #define DUK_TOK_EXP_EQ                            92
3790 #define DUK_TOK_ALSHIFT_EQ                        93
3791 #define DUK_TOK_ARSHIFT_EQ                        94
3792 #define DUK_TOK_RSHIFT_EQ                         95
3793 #define DUK_TOK_BAND_EQ                           96
3794 #define DUK_TOK_BOR_EQ                            97
3795 #define DUK_TOK_BXOR_EQ                           98
3796
3797 /* literals (E5 Section 7.8), except null, true, false, which are treated
3798  * like reserved words (above).
3799  */
3800 #define DUK_TOK_NUMBER                            99
3801 #define DUK_TOK_STRING                            100
3802 #define DUK_TOK_REGEXP                            101
3803
3804 #define DUK_TOK_MAXVAL                            101  /* inclusive */
3805
3806 #define DUK_TOK_INVALID                           DUK_SMALL_UINT_MAX
3807
3808 /* Convert heap string index to a token (reserved words) */
3809 #define DUK_STRIDX_TO_TOK(x)                        ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
3810
3811 /* Sanity check */
3812 #if (DUK_TOK_MAXVAL > 255)
3813 #error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits
3814 #endif
3815
3816 /* Sanity checks for string and token defines */
3817 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK)
3818 #error mismatch in token defines
3819 #endif
3820 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE)
3821 #error mismatch in token defines
3822 #endif
3823 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH)
3824 #error mismatch in token defines
3825 #endif
3826 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE)
3827 #error mismatch in token defines
3828 #endif
3829 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER)
3830 #error mismatch in token defines
3831 #endif
3832 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT)
3833 #error mismatch in token defines
3834 #endif
3835 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE)
3836 #error mismatch in token defines
3837 #endif
3838 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO)
3839 #error mismatch in token defines
3840 #endif
3841 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE)
3842 #error mismatch in token defines
3843 #endif
3844 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY)
3845 #error mismatch in token defines
3846 #endif
3847 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR)
3848 #error mismatch in token defines
3849 #endif
3850 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION)
3851 #error mismatch in token defines
3852 #endif
3853 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF)
3854 #error mismatch in token defines
3855 #endif
3856 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN)
3857 #error mismatch in token defines
3858 #endif
3859 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF)
3860 #error mismatch in token defines
3861 #endif
3862 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW)
3863 #error mismatch in token defines
3864 #endif
3865 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN)
3866 #error mismatch in token defines
3867 #endif
3868 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH)
3869 #error mismatch in token defines
3870 #endif
3871 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS)
3872 #error mismatch in token defines
3873 #endif
3874 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW)
3875 #error mismatch in token defines
3876 #endif
3877 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY)
3878 #error mismatch in token defines
3879 #endif
3880 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF)
3881 #error mismatch in token defines
3882 #endif
3883 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR)
3884 #error mismatch in token defines
3885 #endif
3886 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID)
3887 #error mismatch in token defines
3888 #endif
3889 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE)
3890 #error mismatch in token defines
3891 #endif
3892 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH)
3893 #error mismatch in token defines
3894 #endif
3895 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS)
3896 #error mismatch in token defines
3897 #endif
3898 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST)
3899 #error mismatch in token defines
3900 #endif
3901 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM)
3902 #error mismatch in token defines
3903 #endif
3904 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT)
3905 #error mismatch in token defines
3906 #endif
3907 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS)
3908 #error mismatch in token defines
3909 #endif
3910 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT)
3911 #error mismatch in token defines
3912 #endif
3913 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER)
3914 #error mismatch in token defines
3915 #endif
3916 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL)
3917 #error mismatch in token defines
3918 #endif
3919 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE)
3920 #error mismatch in token defines
3921 #endif
3922 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE)
3923 #error mismatch in token defines
3924 #endif
3925 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS)
3926 #error mismatch in token defines
3927 #endif
3928 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE)
3929 #error mismatch in token defines
3930 #endif
3931 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET)
3932 #error mismatch in token defines
3933 #endif
3934 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE)
3935 #error mismatch in token defines
3936 #endif
3937 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE)
3938 #error mismatch in token defines
3939 #endif
3940 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED)
3941 #error mismatch in token defines
3942 #endif
3943 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC)
3944 #error mismatch in token defines
3945 #endif
3946 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC)
3947 #error mismatch in token defines
3948 #endif
3949 #if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD)
3950 #error mismatch in token defines
3951 #endif
3952
3953 /* Regexp tokens */
3954 #define DUK_RETOK_EOF                              0
3955 #define DUK_RETOK_DISJUNCTION                      1
3956 #define DUK_RETOK_QUANTIFIER                       2
3957 #define DUK_RETOK_ASSERT_START                     3
3958 #define DUK_RETOK_ASSERT_END                       4
3959 #define DUK_RETOK_ASSERT_WORD_BOUNDARY             5
3960 #define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY         6
3961 #define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD       7
3962 #define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD       8
3963 #define DUK_RETOK_ATOM_PERIOD                      9
3964 #define DUK_RETOK_ATOM_CHAR                        10
3965 #define DUK_RETOK_ATOM_DIGIT                       11  /* assumptions in regexp compiler */
3966 #define DUK_RETOK_ATOM_NOT_DIGIT                   12  /* -""- */
3967 #define DUK_RETOK_ATOM_WHITE                       13  /* -""- */
3968 #define DUK_RETOK_ATOM_NOT_WHITE                   14  /* -""- */
3969 #define DUK_RETOK_ATOM_WORD_CHAR                   15  /* -""- */
3970 #define DUK_RETOK_ATOM_NOT_WORD_CHAR               16  /* -""- */
3971 #define DUK_RETOK_ATOM_BACKREFERENCE               17
3972 #define DUK_RETOK_ATOM_START_CAPTURE_GROUP         18
3973 #define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP      19
3974 #define DUK_RETOK_ATOM_START_CHARCLASS             20
3975 #define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED    21
3976 #define DUK_RETOK_ATOM_END_GROUP                   22
3977
3978 /* Constants for duk_lexer_ctx.buf. */
3979 #define DUK_LEXER_TEMP_BUF_LIMIT                   256
3980
3981 /* A token value.  Can be memcpy()'d, but note that slot1/slot2 values are on the valstack.
3982  * Some fields (like num, str1, str2) are only valid for specific token types and may have
3983  * stale values otherwise.
3984  */
3985 struct duk_token {
3986         duk_small_uint_t t;           /* token type (with reserved word identification) */
3987         duk_small_uint_t t_nores;     /* token type (with reserved words as DUK_TOK_IDENTIFER) */
3988         duk_double_t num;             /* numeric value of token */
3989         duk_hstring *str1;            /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
3990         duk_hstring *str2;            /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
3991         duk_size_t start_offset;      /* start byte offset of token in lexer input */
3992         duk_int_t start_line;         /* start line of token (first char) */
3993         duk_int_t num_escapes;        /* number of escapes and line continuations (for directive prologue) */
3994         duk_bool_t lineterm;          /* token was preceded by a lineterm */
3995         duk_bool_t allow_auto_semi;   /* token allows automatic semicolon insertion (eof or preceded by newline) */
3996 };
3997
3998 #define DUK_RE_QUANTIFIER_INFINITE         ((duk_uint32_t) 0xffffffffUL)
3999
4000 /* A regexp token value. */
4001 struct duk_re_token {
4002         duk_small_uint_t t;          /* token type */
4003         duk_small_uint_t greedy;
4004         duk_uint32_t num;            /* numeric value (character, count) */
4005         duk_uint32_t qmin;
4006         duk_uint32_t qmax;
4007 };
4008
4009 /* A structure for 'snapshotting' a point for rewinding */
4010 struct duk_lexer_point {
4011         duk_size_t offset;
4012         duk_int_t line;
4013 };
4014
4015 /* Lexer codepoint with additional info like offset/line number */
4016 struct duk_lexer_codepoint {
4017         duk_codepoint_t codepoint;
4018         duk_size_t offset;
4019         duk_int_t line;
4020 };
4021
4022 /* Lexer context.  Same context is used for ECMAScript and Regexp parsing. */
4023 struct duk_lexer_ctx {
4024 #if defined(DUK_USE_LEXER_SLIDING_WINDOW)
4025         duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */
4026         duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE];
4027 #else
4028         duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */
4029 #endif
4030
4031         duk_hthread *thr;                              /* thread; minimizes argument passing */
4032
4033         const duk_uint8_t *input;                      /* input string (may be a user pointer) */
4034         duk_size_t input_length;                       /* input byte length */
4035         duk_size_t input_offset;                       /* input offset for window leading edge (not window[0]) */
4036         duk_int_t input_line;                          /* input linenumber at input_offset (not window[0]), init to 1 */
4037
4038         duk_idx_t slot1_idx;                           /* valstack slot for 1st token value */
4039         duk_idx_t slot2_idx;                           /* valstack slot for 2nd token value */
4040         duk_idx_t buf_idx;                             /* valstack slot for temp buffer */
4041         duk_hbuffer_dynamic *buf;                      /* temp accumulation buffer */
4042         duk_bufwriter_ctx bw;                          /* bufwriter for temp accumulation */
4043
4044         duk_int_t token_count;                         /* number of tokens parsed */
4045         duk_int_t token_limit;                         /* maximum token count before error (sanity backstop) */
4046
4047         duk_small_uint_t flags;                        /* lexer flags, use compiler flag defines for now */
4048 };
4049
4050 /*
4051  *  Prototypes
4052  */
4053
4054 DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
4055
4056 DUK_INTERNAL_DECL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
4057 DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
4058
4059 DUK_INTERNAL_DECL
4060 void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
4061                                       duk_token *out_token,
4062                                       duk_bool_t strict_mode,
4063                                       duk_bool_t regexp_mode);
4064 #if defined(DUK_USE_REGEXP_SUPPORT)
4065 DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
4066 DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
4067 #endif  /* DUK_USE_REGEXP_SUPPORT */
4068
4069 #endif  /* DUK_LEXER_H_INCLUDED */
4070 /* #include duk_js_compiler.h */
4071 #line 1 "duk_js_compiler.h"
4072 /*
4073  *  ECMAScript compiler.
4074  */
4075
4076 #if !defined(DUK_JS_COMPILER_H_INCLUDED)
4077 #define DUK_JS_COMPILER_H_INCLUDED
4078
4079 /* ECMAScript compiler limits */
4080 #define DUK_COMPILER_TOKEN_LIMIT           100000000L  /* 1e8: protects against deeply nested inner functions */
4081
4082 /* maximum loopcount for peephole optimization */
4083 #define DUK_COMPILER_PEEPHOLE_MAXITER      3
4084
4085 /* maximum bytecode length in instructions */
4086 #define DUK_COMPILER_MAX_BYTECODE_LENGTH   (256L * 1024L * 1024L)  /* 1 GB */
4087
4088 /*
4089  *  Compiler intermediate values
4090  *
4091  *  Intermediate values describe either plain values (e.g. strings or
4092  *  numbers) or binary operations which have not yet been coerced into
4093  *  either a left-hand-side or right-hand-side role (e.g. object property).
4094  */
4095
4096 #define DUK_IVAL_NONE          0   /* no value */
4097 #define DUK_IVAL_PLAIN         1   /* register, constant, or value */
4098 #define DUK_IVAL_ARITH         2   /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
4099 #define DUK_IVAL_PROP          3   /* property access */
4100 #define DUK_IVAL_VAR           4   /* variable access */
4101
4102 #define DUK_ISPEC_NONE         0   /* no value */
4103 #define DUK_ISPEC_VALUE        1   /* value resides in 'valstack_idx' */
4104 #define DUK_ISPEC_REGCONST     2   /* value resides in a register or constant */
4105
4106 /* Bit mask which indicates that a regconst is a constant instead of a register.
4107  * Chosen so that when a regconst is cast to duk_int32_t, all consts are
4108  * negative values.
4109  */
4110 #define DUK_REGCONST_CONST_MARKER    DUK_INT32_MIN  /* = -0x80000000 */
4111
4112 /* Type to represent a reg/const reference during compilation, with <0
4113  * indicating a constant.  Some call sites also use -1 to indicate 'none'.
4114  */
4115 typedef duk_int32_t duk_regconst_t;
4116
4117 typedef struct {
4118         duk_small_uint_t t;          /* DUK_ISPEC_XXX */
4119         duk_regconst_t regconst;
4120         duk_idx_t valstack_idx;      /* always set; points to a reserved valstack slot */
4121 } duk_ispec;
4122
4123 typedef struct {
4124         /*
4125          *  PLAIN: x1
4126          *  ARITH: x1 <op> x2
4127          *  PROP: x1.x2
4128          *  VAR: x1 (name)
4129          */
4130
4131         /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */
4132         duk_small_uint_t t;          /* DUK_IVAL_XXX */
4133         duk_small_uint_t op;         /* bytecode opcode for binary ops */
4134         duk_ispec x1;
4135         duk_ispec x2;
4136 } duk_ivalue;
4137
4138 /*
4139  *  Bytecode instruction representation during compilation
4140  *
4141  *  Contains the actual instruction and (optionally) debug info.
4142  */
4143
4144 struct duk_compiler_instr {
4145         duk_instr_t ins;
4146 #if defined(DUK_USE_PC2LINE)
4147         duk_uint32_t line;
4148 #endif
4149 };
4150
4151 /*
4152  *  Compiler state
4153  */
4154
4155 #define DUK_LABEL_FLAG_ALLOW_BREAK       (1U << 0)
4156 #define DUK_LABEL_FLAG_ALLOW_CONTINUE    (1U << 1)
4157
4158 #define DUK_DECL_TYPE_VAR                0
4159 #define DUK_DECL_TYPE_FUNC               1
4160
4161 /* XXX: optimize to 16 bytes */
4162 typedef struct {
4163         duk_small_uint_t flags;
4164         duk_int_t label_id;          /* numeric label_id (-1 reserved as marker) */
4165         duk_hstring *h_label;        /* borrowed label name */
4166         duk_int_t catch_depth;       /* catch depth at point of definition */
4167         duk_int_t pc_label;          /* pc of label statement:
4168                                       * pc+1: break jump site
4169                                       * pc+2: continue jump site
4170                                       */
4171
4172         /* Fast jumps (which avoid longjmp) jump directly to the jump sites
4173          * which are always known even while the iteration/switch statement
4174          * is still being parsed.  A final peephole pass "straightens out"
4175          * the jumps.
4176          */
4177 } duk_labelinfo;
4178
4179 /* Compiling state of one function, eventually converted to duk_hcompfunc */
4180 struct duk_compiler_func {
4181         /* These pointers are at the start of the struct so that they pack
4182          * nicely.  Mixing pointers and integer values is bad on some
4183          * platforms (e.g. if int is 32 bits and pointers are 64 bits).
4184          */
4185
4186         duk_bufwriter_ctx bw_code;          /* bufwriter for code */
4187
4188         duk_hstring *h_name;                /* function name (borrowed reference), ends up in _name */
4189         /* h_code: held in bw_code */
4190         duk_hobject *h_consts;              /* array */
4191         duk_hobject *h_funcs;               /* array of function templates: [func1, offset1, line1, func2, offset2, line2]
4192                                              * offset/line points to closing brace to allow skipping on pass 2
4193                                              */
4194         duk_hobject *h_decls;               /* array of declarations: [ name1, val1, name2, val2, ... ]
4195                                              * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars)
4196                                              * record function and variable declarations in pass 1
4197                                              */
4198         duk_hobject *h_labelnames;          /* array of active label names */
4199         duk_hbuffer_dynamic *h_labelinfos;  /* C array of duk_labelinfo */
4200         duk_hobject *h_argnames;            /* array of formal argument names (-> _Formals) */
4201         duk_hobject *h_varmap;              /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
4202
4203         /* Value stack indices for tracking objects. */
4204         /* code_idx: not needed */
4205         duk_idx_t consts_idx;
4206         duk_idx_t funcs_idx;
4207         duk_idx_t decls_idx;
4208         duk_idx_t labelnames_idx;
4209         duk_idx_t labelinfos_idx;
4210         duk_idx_t argnames_idx;
4211         duk_idx_t varmap_idx;
4212
4213         /* Temp reg handling. */
4214         duk_regconst_t temp_first;           /* first register that is a temporary (below: variables) */
4215         duk_regconst_t temp_next;            /* next temporary register to allocate */
4216         duk_regconst_t temp_max;             /* highest value of temp_reg (temp_max - 1 is highest used reg) */
4217
4218         /* Shuffle registers if large number of regs/consts. */
4219         duk_regconst_t shuffle1;
4220         duk_regconst_t shuffle2;
4221         duk_regconst_t shuffle3;
4222
4223         /* Stats for current expression being parsed. */
4224         duk_int_t nud_count;
4225         duk_int_t led_count;
4226         duk_int_t paren_level;              /* parenthesis count, 0 = top level */
4227         duk_bool_t expr_lhs;                /* expression is left-hand-side compatible */
4228         duk_bool_t allow_in;                /* current paren level allows 'in' token */
4229
4230         /* Misc. */
4231         duk_int_t stmt_next;                /* statement id allocation (running counter) */
4232         duk_int_t label_next;               /* label id allocation (running counter) */
4233         duk_int_t catch_depth;              /* catch stack depth */
4234         duk_int_t with_depth;               /* with stack depth (affects identifier lookups) */
4235         duk_int_t fnum_next;                /* inner function numbering */
4236         duk_int_t num_formals;              /* number of formal arguments */
4237         duk_regconst_t reg_stmt_value;      /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
4238 #if defined(DUK_USE_DEBUGGER_SUPPORT)
4239         duk_int_t min_line;                 /* XXX: typing (duk_hcompfunc has duk_uint32_t) */
4240         duk_int_t max_line;
4241 #endif
4242
4243         /* Status booleans. */
4244         duk_uint8_t is_function;             /* is an actual function (not global/eval code) */
4245         duk_uint8_t is_eval;                 /* is eval code */
4246         duk_uint8_t is_global;               /* is global code */
4247         duk_uint8_t is_namebinding;          /* needs a name binding */
4248         duk_uint8_t is_constructable;        /* result is constructable */
4249         duk_uint8_t is_setget;               /* is a setter/getter */
4250         duk_uint8_t is_strict;               /* function is strict */
4251         duk_uint8_t is_notail;               /* function must not be tail called */
4252         duk_uint8_t in_directive_prologue;   /* parsing in "directive prologue", recognize directives */
4253         duk_uint8_t in_scanning;             /* parsing in "scanning" phase (first pass) */
4254         duk_uint8_t may_direct_eval;         /* function may call direct eval */
4255         duk_uint8_t id_access_arguments;     /* function refers to 'arguments' identifier */
4256         duk_uint8_t id_access_slow;          /* function makes one or more slow path accesses that won't match own static variables */
4257         duk_uint8_t id_access_slow_own;      /* function makes one or more slow path accesses that may match own static variables */
4258         duk_uint8_t is_arguments_shadowed;   /* argument/function declaration shadows 'arguments' */
4259         duk_uint8_t needs_shuffle;           /* function needs shuffle registers */
4260         duk_uint8_t reject_regexp_in_adv;    /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
4261         duk_uint8_t allow_regexp_in_adv;     /* allow RegExp literal on next advance() call */
4262 };
4263
4264 struct duk_compiler_ctx {
4265         duk_hthread *thr;
4266
4267         /* filename being compiled (ends up in functions' '_filename' property) */
4268         duk_hstring *h_filename;            /* borrowed reference */
4269
4270         /* lexing (tokenization) state (contains two valstack slot indices) */
4271         duk_lexer_ctx lex;
4272
4273         /* current and previous token for parsing */
4274         duk_token prev_token;
4275         duk_token curr_token;
4276         duk_idx_t tok11_idx;                /* curr_token slot1 (matches 'lex' slot1_idx) */
4277         duk_idx_t tok12_idx;                /* curr_token slot2 (matches 'lex' slot2_idx) */
4278         duk_idx_t tok21_idx;                /* prev_token slot1 */
4279         duk_idx_t tok22_idx;                /* prev_token slot2 */
4280
4281         /* recursion limit */
4282         duk_int_t recursion_depth;
4283         duk_int_t recursion_limit;
4284
4285         /* code emission temporary */
4286         duk_int_t emit_jumpslot_pc;
4287
4288         /* current function being compiled (embedded instead of pointer for more compact access) */
4289         duk_compiler_func curr_func;
4290 };
4291
4292 /*
4293  *  Prototypes
4294  */
4295
4296 DUK_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);
4297
4298 #endif  /* DUK_JS_COMPILER_H_INCLUDED */
4299 /* #include duk_regexp.h */
4300 #line 1 "duk_regexp.h"
4301 /*
4302  *  Regular expression structs, constants, and bytecode defines.
4303  */
4304
4305 #if !defined(DUK_REGEXP_H_INCLUDED)
4306 #define DUK_REGEXP_H_INCLUDED
4307
4308 /* maximum bytecode copies for {n,m} quantifiers */
4309 #define DUK_RE_MAX_ATOM_COPIES             1000
4310
4311 /* regexp compilation limits */
4312 #define DUK_RE_COMPILE_TOKEN_LIMIT         100000000L   /* 1e8 */
4313
4314 /* regexp execution limits */
4315 #define DUK_RE_EXECUTE_STEPS_LIMIT         1000000000L  /* 1e9 */
4316
4317 /* regexp opcodes */
4318 #define DUK_REOP_MATCH                     1
4319 #define DUK_REOP_CHAR                      2
4320 #define DUK_REOP_PERIOD                    3
4321 #define DUK_REOP_RANGES                    4
4322 #define DUK_REOP_INVRANGES                 5
4323 #define DUK_REOP_JUMP                      6
4324 #define DUK_REOP_SPLIT1                    7
4325 #define DUK_REOP_SPLIT2                    8
4326 #define DUK_REOP_SQMINIMAL                 9
4327 #define DUK_REOP_SQGREEDY                  10
4328 #define DUK_REOP_SAVE                      11
4329 #define DUK_REOP_WIPERANGE                 12
4330 #define DUK_REOP_LOOKPOS                   13
4331 #define DUK_REOP_LOOKNEG                   14
4332 #define DUK_REOP_BACKREFERENCE             15
4333 #define DUK_REOP_ASSERT_START              16
4334 #define DUK_REOP_ASSERT_END                17
4335 #define DUK_REOP_ASSERT_WORD_BOUNDARY      18
4336 #define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY  19
4337
4338 /* flags */
4339 #define DUK_RE_FLAG_GLOBAL                 (1U << 0)
4340 #define DUK_RE_FLAG_IGNORE_CASE            (1U << 1)
4341 #define DUK_RE_FLAG_MULTILINE              (1U << 2)
4342
4343 struct duk_re_matcher_ctx {
4344         duk_hthread *thr;
4345
4346         duk_uint32_t re_flags;
4347         const duk_uint8_t *input;
4348         const duk_uint8_t *input_end;
4349         const duk_uint8_t *bytecode;
4350         const duk_uint8_t *bytecode_end;
4351         const duk_uint8_t **saved;  /* allocated from valstack (fixed buffer) */
4352         duk_uint32_t nsaved;
4353         duk_uint32_t recursion_depth;
4354         duk_uint32_t recursion_limit;
4355         duk_uint32_t steps_count;
4356         duk_uint32_t steps_limit;
4357 };
4358
4359 struct duk_re_compiler_ctx {
4360         duk_hthread *thr;
4361
4362         duk_uint32_t re_flags;
4363         duk_lexer_ctx lex;
4364         duk_re_token curr_token;
4365         duk_bufwriter_ctx bw;
4366         duk_uint32_t captures;  /* highest capture number emitted so far (used as: ++captures) */
4367         duk_uint32_t highest_backref;
4368         duk_uint32_t recursion_depth;
4369         duk_uint32_t recursion_limit;
4370         duk_uint32_t nranges;  /* internal temporary value, used for char classes */
4371 };
4372
4373 /*
4374  *  Prototypes
4375  */
4376
4377 #if defined(DUK_USE_REGEXP_SUPPORT)
4378 DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr);
4379 DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr);
4380 DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr);
4381 DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr);  /* hacky helper for String.prototype.split() */
4382 #endif
4383
4384 #endif  /* DUK_REGEXP_H_INCLUDED */
4385 /* #include duk_heaphdr.h */
4386 #line 1 "duk_heaphdr.h"
4387 /*
4388  *  Heap header definition and assorted macros, including ref counting.
4389  *  Access all fields through the accessor macros.
4390  */
4391
4392 #if !defined(DUK_HEAPHDR_H_INCLUDED)
4393 #define DUK_HEAPHDR_H_INCLUDED
4394
4395 /*
4396  *  Common heap header
4397  *
4398  *  All heap objects share the same flags and refcount fields.  Objects other
4399  *  than strings also need to have a single or double linked list pointers
4400  *  for insertion into the "heap allocated" list.  Strings have single linked
4401  *  list pointers for string table chaining.
4402  *
4403  *  Technically, 'h_refcount' must be wide enough to guarantee that it cannot
4404  *  wrap; otherwise objects might be freed incorrectly after wrapping.  The
4405  *  default refcount field is 32 bits even on 64-bit systems: while that's in
4406  *  theory incorrect, the Duktape heap needs to be larger than 64GB for the
4407  *  count to actually wrap (assuming 16-byte duk_tvals).  This is very unlikely
4408  *  to ever be an issue, but if it is, disabling DUK_USE_REFCOUNT32 causes
4409  *  Duktape to use size_t for refcounts which should always be safe.
4410  *
4411  *  Heap header size on 32-bit platforms: 8 bytes without reference counting,
4412  *  16 bytes with reference counting.
4413  *
4414  *  Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
4415  *  defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined()
4416  *  around them.
4417  */
4418
4419 /* XXX: macro for shared header fields (avoids some padding issues) */
4420
4421 struct duk_heaphdr {
4422         duk_uint32_t h_flags;
4423
4424 #if defined(DUK_USE_REFERENCE_COUNTING)
4425 #if defined(DUK_USE_ASSERTIONS)
4426         /* When assertions enabled, used by mark-and-sweep for refcount
4427          * validation.  Largest reasonable type; also detects overflows.
4428          */
4429         duk_size_t h_assert_refcount;
4430 #endif
4431 #if defined(DUK_USE_REFCOUNT16)
4432         duk_uint16_t h_refcount;
4433 #elif defined(DUK_USE_REFCOUNT32)
4434         duk_uint32_t h_refcount;
4435 #else
4436         duk_size_t h_refcount;
4437 #endif
4438 #endif  /* DUK_USE_REFERENCE_COUNTING */
4439
4440 #if defined(DUK_USE_HEAPPTR16)
4441         duk_uint16_t h_next16;
4442 #else
4443         duk_heaphdr *h_next;
4444 #endif
4445
4446 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
4447         /* refcounting requires direct heap frees, which in turn requires a dual linked heap */
4448 #if defined(DUK_USE_HEAPPTR16)
4449         duk_uint16_t h_prev16;
4450 #else
4451         duk_heaphdr *h_prev;
4452 #endif
4453 #endif
4454
4455         /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the
4456          * struct won't align nicely to 4 bytes.  This 16-bit extra field
4457          * is added to make the alignment clean; the field can be used by
4458          * heap objects when 16-bit packing is used.  This field is now
4459          * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be
4460          * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP;
4461          * this only matter to low memory environments anyway.
4462          */
4463 #if defined(DUK_USE_HEAPPTR16)
4464         duk_uint16_t h_extra16;
4465 #endif
4466 };
4467
4468 struct duk_heaphdr_string {
4469         /* 16 bits would be enough for shared heaphdr flags and duk_hstring
4470          * flags.  The initial parts of duk_heaphdr_string and duk_heaphdr
4471          * must match so changing the flags field size here would be quite
4472          * awkward.  However, to minimize struct size, we can pack at least
4473          * 16 bits of duk_hstring data into the flags field.
4474          */
4475         duk_uint32_t h_flags;
4476
4477 #if defined(DUK_USE_REFERENCE_COUNTING)
4478 #if defined(DUK_USE_ASSERTIONS)
4479         /* When assertions enabled, used by mark-and-sweep for refcount
4480          * validation.  Largest reasonable type; also detects overflows.
4481          */
4482         duk_size_t h_assert_refcount;
4483 #endif
4484 #if defined(DUK_USE_REFCOUNT16)
4485         duk_uint16_t h_refcount;
4486         duk_uint16_t h_strextra16;  /* round out to 8 bytes */
4487 #elif defined(DUK_USE_REFCOUNT32)
4488         duk_uint32_t h_refcount;
4489 #else
4490         duk_size_t h_refcount;
4491 #endif
4492 #else
4493         duk_uint16_t h_strextra16;
4494 #endif  /* DUK_USE_REFERENCE_COUNTING */
4495
4496         duk_hstring *h_next;
4497         /* No 'h_prev' pointer for strings. */
4498 };
4499
4500 #define DUK_HEAPHDR_FLAGS_TYPE_MASK      0x00000003UL
4501 #define DUK_HEAPHDR_FLAGS_FLAG_MASK      (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
4502
4503                                              /* 2 bits for heap type */
4504 #define DUK_HEAPHDR_FLAGS_HEAP_START     2   /* 5 heap flags */
4505 #define DUK_HEAPHDR_FLAGS_USER_START     7   /* 25 user flags */
4506
4507 #define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n)  (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
4508 #define DUK_HEAPHDR_USER_FLAG_NUMBER(n)  (DUK_HEAPHDR_FLAGS_USER_START + (n))
4509 #define DUK_HEAPHDR_HEAP_FLAG(n)         (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
4510 #define DUK_HEAPHDR_USER_FLAG(n)         (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
4511
4512 #define DUK_HEAPHDR_FLAG_REACHABLE       DUK_HEAPHDR_HEAP_FLAG(0)  /* mark-and-sweep: reachable */
4513 #define DUK_HEAPHDR_FLAG_TEMPROOT        DUK_HEAPHDR_HEAP_FLAG(1)  /* mark-and-sweep: children not processed */
4514 #define DUK_HEAPHDR_FLAG_FINALIZABLE     DUK_HEAPHDR_HEAP_FLAG(2)  /* mark-and-sweep: finalizable (on current pass) */
4515 #define DUK_HEAPHDR_FLAG_FINALIZED       DUK_HEAPHDR_HEAP_FLAG(3)  /* mark-and-sweep: finalized (on previous pass) */
4516 #define DUK_HEAPHDR_FLAG_READONLY        DUK_HEAPHDR_HEAP_FLAG(4)  /* read-only object, in code section */
4517
4518 #define DUK_HTYPE_MIN                    0
4519 #define DUK_HTYPE_STRING                 0
4520 #define DUK_HTYPE_OBJECT                 1
4521 #define DUK_HTYPE_BUFFER                 2
4522 #define DUK_HTYPE_MAX                    2
4523
4524 #if defined(DUK_USE_HEAPPTR16)
4525 #define DUK_HEAPHDR_GET_NEXT(heap,h) \
4526         ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16))
4527 #define DUK_HEAPHDR_SET_NEXT(heap,h,val)   do { \
4528                 (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \
4529         } while (0)
4530 #else
4531 #define DUK_HEAPHDR_GET_NEXT(heap,h)  ((h)->h_next)
4532 #define DUK_HEAPHDR_SET_NEXT(heap,h,val)   do { \
4533                 (h)->h_next = (val); \
4534         } while (0)
4535 #endif
4536
4537 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
4538 #if defined(DUK_USE_HEAPPTR16)
4539 #define DUK_HEAPHDR_GET_PREV(heap,h) \
4540         ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16))
4541 #define DUK_HEAPHDR_SET_PREV(heap,h,val)   do { \
4542                 (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \
4543         } while (0)
4544 #else
4545 #define DUK_HEAPHDR_GET_PREV(heap,h)       ((h)->h_prev)
4546 #define DUK_HEAPHDR_SET_PREV(heap,h,val)   do { \
4547                 (h)->h_prev = (val); \
4548         } while (0)
4549 #endif
4550 #endif
4551
4552 #if defined(DUK_USE_REFERENCE_COUNTING)
4553 #define DUK_HEAPHDR_GET_REFCOUNT(h)   ((h)->h_refcount)
4554 #define DUK_HEAPHDR_SET_REFCOUNT(h,val)  do { \
4555                 (h)->h_refcount = (val); \
4556                 DUK_ASSERT((h)->h_refcount == (val));  /* No truncation. */ \
4557         } while (0)
4558 #define DUK_HEAPHDR_PREINC_REFCOUNT(h)  (++(h)->h_refcount)  /* result: updated refcount */
4559 #define DUK_HEAPHDR_PREDEC_REFCOUNT(h)  (--(h)->h_refcount)  /* result: updated refcount */
4560 #else
4561 /* refcount macros not defined without refcounting, caller must #if defined() now */
4562 #endif  /* DUK_USE_REFERENCE_COUNTING */
4563
4564 /*
4565  *  Note: type is treated as a field separate from flags, so some masking is
4566  *  involved in the macros below.
4567  */
4568
4569 #define DUK_HEAPHDR_GET_FLAGS_RAW(h)  ((h)->h_flags)
4570 #define DUK_HEAPHDR_SET_FLAGS_RAW(h,val)  do { \
4571                 (h)->h_flags = (val); } \
4572         }
4573 #define DUK_HEAPHDR_GET_FLAGS(h)      ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
4574 #define DUK_HEAPHDR_SET_FLAGS(h,val)  do { \
4575                 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
4576         } while (0)
4577 #define DUK_HEAPHDR_GET_TYPE(h)       ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
4578 #define DUK_HEAPHDR_SET_TYPE(h,val)   do { \
4579                 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
4580         } while (0)
4581
4582 /* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero
4583  * and the comparison is unsigned, it's always true and generates warnings.
4584  */
4585 #define DUK_HEAPHDR_HTYPE_VALID(h)    ( \
4586         DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
4587         )
4588
4589 #define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval)  do { \
4590                 (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
4591                                ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
4592         } while (0)
4593
4594 #define DUK_HEAPHDR_SET_FLAG_BITS(h,bits)  do { \
4595                 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
4596                 (h)->h_flags |= (bits); \
4597         } while (0)
4598
4599 #define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits)  do { \
4600                 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
4601                 (h)->h_flags &= ~((bits)); \
4602         } while (0)
4603
4604 #define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits)  (((h)->h_flags & (bits)) != 0)
4605
4606 #define DUK_HEAPHDR_SET_REACHABLE(h)      DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
4607 #define DUK_HEAPHDR_CLEAR_REACHABLE(h)    DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
4608 #define DUK_HEAPHDR_HAS_REACHABLE(h)      DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
4609
4610 #define DUK_HEAPHDR_SET_TEMPROOT(h)       DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
4611 #define DUK_HEAPHDR_CLEAR_TEMPROOT(h)     DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
4612 #define DUK_HEAPHDR_HAS_TEMPROOT(h)       DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
4613
4614 #define DUK_HEAPHDR_SET_FINALIZABLE(h)    DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
4615 #define DUK_HEAPHDR_CLEAR_FINALIZABLE(h)  DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
4616 #define DUK_HEAPHDR_HAS_FINALIZABLE(h)    DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
4617
4618 #define DUK_HEAPHDR_SET_FINALIZED(h)      DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
4619 #define DUK_HEAPHDR_CLEAR_FINALIZED(h)    DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
4620 #define DUK_HEAPHDR_HAS_FINALIZED(h)      DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
4621
4622 #define DUK_HEAPHDR_SET_READONLY(h)       DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
4623 #define DUK_HEAPHDR_CLEAR_READONLY(h)     DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
4624 #define DUK_HEAPHDR_HAS_READONLY(h)       DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
4625
4626 /* get or set a range of flags; m=first bit number, n=number of bits */
4627 #define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n)  (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL))
4628
4629 #define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v)  do { \
4630                 (h)->h_flags = \
4631                         ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \
4632                         | ((v) << (m)); \
4633         } while (0)
4634
4635 /* init pointer fields to null */
4636 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
4637 #define DUK_HEAPHDR_INIT_NULLS(h)       do { \
4638                 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
4639                 DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \
4640         } while (0)
4641 #else
4642 #define DUK_HEAPHDR_INIT_NULLS(h)       do { \
4643                 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
4644         } while (0)
4645 #endif
4646
4647 #define DUK_HEAPHDR_STRING_INIT_NULLS(h)  do { \
4648                 (h)->h_next = NULL; \
4649         } while (0)
4650
4651 /*
4652  *  Type tests
4653  */
4654
4655 /* Take advantage of the fact that for DUK_HTYPE_xxx numbers the lowest bit
4656  * is only set for DUK_HTYPE_OBJECT (= 1).
4657  */
4658 #if 0
4659 #define DUK_HEAPHDR_IS_OBJECT(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT)
4660 #endif
4661 #define DUK_HEAPHDR_IS_OBJECT(h) ((h)->h_flags & 0x01UL)
4662 #define DUK_HEAPHDR_IS_STRING(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING)
4663 #define DUK_HEAPHDR_IS_BUFFER(h) (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER)
4664
4665 /*
4666  *  Assert helpers
4667  */
4668
4669 /* Check that prev/next links are consistent: if e.g. h->prev is != NULL,
4670  * h->prev->next should point back to h.
4671  */
4672 #if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_ASSERTIONS)
4673 #define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do { \
4674                 if ((h) != NULL) { \
4675                         duk_heaphdr *h__prev, *h__next; \
4676                         h__prev = DUK_HEAPHDR_GET_PREV((heap), (h)); \
4677                         h__next = DUK_HEAPHDR_GET_NEXT((heap), (h)); \
4678                         DUK_ASSERT(h__prev == NULL || (DUK_HEAPHDR_GET_NEXT((heap), h__prev) == (h))); \
4679                         DUK_ASSERT(h__next == NULL || (DUK_HEAPHDR_GET_PREV((heap), h__next) == (h))); \
4680                 } \
4681         } while (0)
4682 #else
4683 #define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0)
4684 #endif
4685
4686 #define DUK_ASSERT_HEAPHDR_VALID(h) do { \
4687                 DUK_ASSERT((h) != NULL); \
4688                 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((h))); \
4689         } while (0)
4690
4691 #endif  /* DUK_HEAPHDR_H_INCLUDED */
4692 /* #include duk_refcount.h */
4693 #line 1 "duk_refcount.h"
4694 /*
4695  *  Reference counting helper macros.  The macros take a thread argument
4696  *  and must thus always be executed in a specific thread context.  The
4697  *  thread argument is not really needed anymore: DECREF can operate with
4698  *  a heap pointer only, and INCREF needs neither.
4699  */
4700
4701 #if !defined(DUK_REFCOUNT_H_INCLUDED)
4702 #define DUK_REFCOUNT_H_INCLUDED
4703
4704 #if defined(DUK_USE_REFERENCE_COUNTING)
4705
4706 #if defined(DUK_USE_ROM_OBJECTS)
4707 /* With ROM objects "needs refcount update" is true when the value is
4708  * heap allocated and is not a ROM object.
4709  */
4710 /* XXX: double evaluation for 'tv' argument. */
4711 #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \
4712         (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv))))
4713 #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h)  (!DUK_HEAPHDR_HAS_READONLY((h)))
4714 #else  /* DUK_USE_ROM_OBJECTS */
4715 /* Without ROM objects "needs refcount update" == is heap allocated. */
4716 #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)    DUK_TVAL_IS_HEAP_ALLOCATED((tv))
4717 #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h)  1
4718 #endif  /* DUK_USE_ROM_OBJECTS */
4719
4720 /* Fast variants, inline refcount operations except for refzero handling.
4721  * Can be used explicitly when speed is always more important than size.
4722  * For a good compiler and a single file build, these are basically the
4723  * same as a forced inline.
4724  */
4725 #define DUK_TVAL_INCREF_FAST(thr,tv) do { \
4726                 duk_tval *duk__tv = (tv); \
4727                 DUK_ASSERT(duk__tv != NULL); \
4728                 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4729                         duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4730                         DUK_ASSERT(duk__h != NULL); \
4731                         DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4732                         DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
4733                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0);  /* No wrapping. */ \
4734                 } \
4735         } while (0)
4736 #define DUK_TVAL_DECREF_FAST(thr,tv) do { \
4737                 duk_tval *duk__tv = (tv); \
4738                 DUK_ASSERT(duk__tv != NULL); \
4739                 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4740                         duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4741                         DUK_ASSERT(duk__h != NULL); \
4742                         DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4743                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4744                         if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4745                                 duk_heaphdr_refzero((thr), duk__h); \
4746                         } \
4747                 } \
4748         } while (0)
4749 #define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \
4750                 duk_tval *duk__tv = (tv); \
4751                 DUK_ASSERT(duk__tv != NULL); \
4752                 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4753                         duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4754                         DUK_ASSERT(duk__h != NULL); \
4755                         DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4756                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4757                         if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4758                                 duk_heaphdr_refzero_norz((thr), duk__h); \
4759                         } \
4760                 } \
4761         } while (0)
4762 #define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
4763                 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
4764                 DUK_ASSERT(duk__h != NULL); \
4765                 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4766                 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
4767                         DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
4768                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) != 0);  /* No wrapping. */ \
4769                 } \
4770         } while (0)
4771 #define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \
4772                 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
4773                 DUK_ASSERT(duk__h != NULL); \
4774                 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4775                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4776                 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
4777                         if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4778                                 (rzcall)((thr), (rzcast) duk__h); \
4779                         } \
4780                 } \
4781         } while (0)
4782 #define DUK_HEAPHDR_DECREF_FAST(thr,h) \
4783         DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
4784 #define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \
4785         DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
4786
4787 /* Slow variants, call to a helper to reduce code size.
4788  * Can be used explicitly when size is always more important than speed.
4789  */
4790 #define DUK_TVAL_INCREF_SLOW(thr,tv)         do { duk_tval_incref((tv)); } while (0)
4791 #define DUK_TVAL_DECREF_SLOW(thr,tv)         do { duk_tval_decref((thr), (tv)); } while (0)
4792 #define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv)    do { duk_tval_decref_norz((thr), (tv)); } while (0)
4793 #define DUK_HEAPHDR_INCREF_SLOW(thr,h)       do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4794 #define DUK_HEAPHDR_DECREF_SLOW(thr,h)       do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4795 #define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h)  do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4796 #define DUK_HSTRING_INCREF_SLOW(thr,h)       do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4797 #define DUK_HSTRING_DECREF_SLOW(thr,h)       do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4798 #define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h)  do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4799 #define DUK_HBUFFER_INCREF_SLOW(thr,h)       do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4800 #define DUK_HBUFFER_DECREF_SLOW(thr,h)       do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4801 #define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h)  do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4802 #define DUK_HOBJECT_INCREF_SLOW(thr,h)       do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4803 #define DUK_HOBJECT_DECREF_SLOW(thr,h)       do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4804 #define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h)  do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4805
4806 /* Default variants.  Selection depends on speed/size preference.
4807  * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
4808  * is about +1kB for _FAST variants.
4809  */
4810 #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
4811 /* XXX: It would be nice to specialize for specific duk_hobject subtypes
4812  * but current refzero queue handling prevents that.
4813  */
4814 #define DUK_TVAL_INCREF(thr,tv)                DUK_TVAL_INCREF_FAST((thr),(tv))
4815 #define DUK_TVAL_DECREF(thr,tv)                DUK_TVAL_DECREF_FAST((thr),(tv))
4816 #define DUK_TVAL_DECREF_NORZ(thr,tv)           DUK_TVAL_DECREF_NORZ_FAST((thr),(tv))
4817 #define DUK_HEAPHDR_INCREF(thr,h)              DUK_HEAPHDR_INCREF_FAST((thr),(h))
4818 #define DUK_HEAPHDR_DECREF(thr,h)              DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
4819 #define DUK_HEAPHDR_DECREF_NORZ(thr,h)         DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
4820 #define DUK_HSTRING_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4821 #define DUK_HSTRING_DECREF(thr,h)              DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *)
4822 #define DUK_HSTRING_DECREF_NORZ(thr,h)         DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *)  /* no 'norz' variant */
4823 #define DUK_HOBJECT_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4824 #define DUK_HOBJECT_DECREF(thr,h)              DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4825 #define DUK_HOBJECT_DECREF_NORZ(thr,h)         DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4826 #define DUK_HBUFFER_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4827 #define DUK_HBUFFER_DECREF(thr,h)              DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *)
4828 #define DUK_HBUFFER_DECREF_NORZ(thr,h)         DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *)  /* no 'norz' variant */
4829 #define DUK_HCOMPFUNC_INCREF(thr,h)            DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4830 #define DUK_HCOMPFUNC_DECREF(thr,h)            DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4831 #define DUK_HCOMPFUNC_DECREF_NORZ(thr,h)       DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4832 #define DUK_HNATFUNC_INCREF(thr,h)             DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4833 #define DUK_HNATFUNC_DECREF(thr,h)             DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4834 #define DUK_HNATFUNC_DECREF_NORZ(thr,h)        DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4835 #define DUK_HBUFOBJ_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4836 #define DUK_HBUFOBJ_DECREF(thr,h)              DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4837 #define DUK_HBUFOBJ_DECREF_NORZ(thr,h)         DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4838 #define DUK_HTHREAD_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4839 #define DUK_HTHREAD_DECREF(thr,h)              DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4840 #define DUK_HTHREAD_DECREF_NORZ(thr,h)         DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4841 #else
4842 #define DUK_TVAL_INCREF(thr,tv)                DUK_TVAL_INCREF_SLOW((thr),(tv))
4843 #define DUK_TVAL_DECREF(thr,tv)                DUK_TVAL_DECREF_SLOW((thr),(tv))
4844 #define DUK_TVAL_DECREF_NORZ(thr,tv)           DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv))
4845 #define DUK_HEAPHDR_INCREF(thr,h)              DUK_HEAPHDR_INCREF_SLOW((thr),(h))
4846 #define DUK_HEAPHDR_DECREF(thr,h)              DUK_HEAPHDR_DECREF_SLOW((thr),(h))
4847 #define DUK_HEAPHDR_DECREF_NORZ(thr,h)         DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h))
4848 #define DUK_HSTRING_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4849 #define DUK_HSTRING_DECREF(thr,h)              DUK_HSTRING_DECREF_SLOW((thr),(h))
4850 #define DUK_HSTRING_DECREF_NORZ(thr,h)         DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h))
4851 #define DUK_HOBJECT_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4852 #define DUK_HOBJECT_DECREF(thr,h)              DUK_HOBJECT_DECREF_SLOW((thr),(h))
4853 #define DUK_HOBJECT_DECREF_NORZ(thr,h)         DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h))
4854 #define DUK_HBUFFER_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4855 #define DUK_HBUFFER_DECREF(thr,h)              DUK_HBUFFER_DECREF_SLOW((thr),(h))
4856 #define DUK_HBUFFER_DECREF_NORZ(thr,h)         DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h))
4857 #define DUK_HCOMPFUNC_INCREF(thr,h)            DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4858 #define DUK_HCOMPFUNC_DECREF(thr,h)            DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4859 #define DUK_HCOMPFUNC_DECREF_NORZ(thr,h)       DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4860 #define DUK_HNATFUNC_INCREF(thr,h)             DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4861 #define DUK_HNATFUNC_DECREF(thr,h)             DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4862 #define DUK_HNATFUNC_DECREF_NORZ(thr,h)        DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4863 #define DUK_HBUFOBJ_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4864 #define DUK_HBUFOBJ_DECREF(thr,h)              DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4865 #define DUK_HBUFOB_DECREF_NORZ(thr,h)          DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4866 #define DUK_HTHREAD_INCREF(thr,h)              DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4867 #define DUK_HTHREAD_DECREF(thr,h)              DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4868 #define DUK_HTHREAD_DECREF_NORZ(thr,h)         DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4869 #endif
4870
4871 /* Convenience for some situations; the above macros don't allow NULLs
4872  * for performance reasons.  Macros cover only actually needed cases.
4873  */
4874 #define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \
4875                 if ((h) != NULL) { \
4876                         DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
4877                 } \
4878         } while (0)
4879 #define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \
4880                 if ((h) != NULL) { \
4881                         DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
4882                 } \
4883         } while (0)
4884 #define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4885                 if ((h) != NULL) { \
4886                         DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \
4887                 } \
4888         } while (0)
4889 #define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
4890                 if ((h) != NULL) { \
4891                         DUK_HOBJECT_INCREF((thr), (h)); \
4892                 } \
4893         } while (0)
4894 #define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
4895                 if ((h) != NULL) { \
4896                         DUK_HOBJECT_DECREF((thr), (h)); \
4897                 } \
4898         } while (0)
4899 #define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4900                 if ((h) != NULL) { \
4901                         DUK_HOBJECT_DECREF_NORZ((thr), (h)); \
4902                 } \
4903         } while (0)
4904 #define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \
4905                 if ((h) != NULL) { \
4906                         DUK_HBUFFER_INCREF((thr), (h)); \
4907                 } \
4908         } while (0)
4909 #define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \
4910                 if ((h) != NULL) { \
4911                         DUK_HBUFFER_DECREF((thr), (h)); \
4912                 } \
4913         } while (0)
4914 #define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4915                 if ((h) != NULL) { \
4916                         DUK_HBUFFER_DECREF_NORZ((thr), (h)); \
4917                 } \
4918         } while (0)
4919 #define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \
4920                 if ((h) != NULL) { \
4921                         DUK_HTHREAD_INCREF((thr), (h)); \
4922                 } \
4923         } while (0)
4924 #define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \
4925                 if ((h) != NULL) { \
4926                         DUK_HTHREAD_DECREF((thr), (h)); \
4927                 } \
4928         } while (0)
4929 #define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4930                 if ((h) != NULL) { \
4931                         DUK_HTHREAD_DECREF_NORZ((thr), (h)); \
4932                 } \
4933         } while (0)
4934
4935 /* Called after one or more DECREF NORZ calls to handle pending side effects.
4936  * At present DECREF NORZ does freeing inline but doesn't execute finalizers,
4937  * so these macros check for pending finalizers and execute them.  The FAST
4938  * variant is performance critical.
4939  */
4940 #if defined(DUK_USE_FINALIZER_SUPPORT)
4941 #define DUK_REFZERO_CHECK_FAST(thr) do { \
4942                 duk_refzero_check_fast((thr)); \
4943         } while (0)
4944 #define DUK_REFZERO_CHECK_SLOW(thr) do { \
4945                 duk_refzero_check_slow((thr)); \
4946         } while (0)
4947 #else  /* DUK_USE_FINALIZER_SUPPORT */
4948 #define DUK_REFZERO_CHECK_FAST(thr) do { } while (0)
4949 #define DUK_REFZERO_CHECK_SLOW(thr) do { } while (0)
4950 #endif  /* DUK_USE_FINALIZER_SUPPORT */
4951
4952 /*
4953  *  Macros to set a duk_tval and update refcount of the target (decref the
4954  *  old value and incref the new value if necessary).  This is both performance
4955  *  and footprint critical; any changes made should be measured for size/speed.
4956  */
4957
4958 #define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
4959                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4960                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4961                 DUK_TVAL_SET_UNDEFINED(tv__dst); \
4962                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
4963         } while (0)
4964
4965 #define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \
4966                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4967                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4968                 DUK_TVAL_SET_UNDEFINED(tv__dst); \
4969                 DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \
4970         } while (0)
4971
4972 #define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
4973                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4974                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4975                 DUK_TVAL_SET_UNUSED(tv__dst); \
4976                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
4977         } while (0)
4978
4979 #define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
4980                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4981                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4982                 DUK_TVAL_SET_NULL(tv__dst); \
4983                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
4984         } while (0)
4985
4986 #define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4987                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4988                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4989                 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
4990                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
4991         } while (0)
4992
4993 #define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4994                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4995                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4996                 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
4997                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
4998         } while (0)
4999 #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5000                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5001                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5002                 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
5003                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5004         } while (0)
5005 #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5006                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5007                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5008                 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
5009                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5010         } while (0)
5011 #define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
5012                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5013                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5014                 DUK_TVAL_SET_NAN(tv__dst); \
5015                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5016         } while (0)
5017 #if defined(DUK_USE_FASTINT)
5018 #define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5019                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5020                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5021                 DUK_TVAL_SET_I48(tv__dst, (newval)); \
5022                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5023         } while (0)
5024 #define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5025                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5026                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5027                 DUK_TVAL_SET_I32(tv__dst, (newval)); \
5028                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5029         } while (0)
5030 #define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5031                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5032                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5033                 DUK_TVAL_SET_U32(tv__dst, (newval)); \
5034                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5035         } while (0)
5036 #else
5037 #define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
5038         DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
5039 #endif  /* DUK_USE_FASTINT */
5040
5041 #define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
5042                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5043                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5044                 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
5045                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5046         } while (0)
5047
5048 #define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5049                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5050                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5051                 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
5052                 DUK_HSTRING_INCREF((thr), (newval)); \
5053                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5054         } while (0)
5055
5056 #define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5057                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5058                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5059                 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
5060                 DUK_HOBJECT_INCREF((thr), (newval)); \
5061                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5062         } while (0)
5063
5064 #define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5065                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5066                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5067                 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
5068                 DUK_HBUFFER_INCREF((thr), (newval)); \
5069                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5070         } while (0)
5071
5072 #define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5073                 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
5074                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5075                 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
5076                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5077         } while (0)
5078
5079 /* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups,
5080  * etc, so it's very important for performance.  Measure when changing.
5081  *
5082  * NOTE: the source and destination duk_tval pointers may be the same, and
5083  * the macros MUST deal with that correctly.
5084  */
5085
5086 /* Original idiom used, minimal code size. */
5087 #define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
5088                 duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
5089                 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
5090                 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
5091                 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
5092                 DUK_TVAL_INCREF((thr), tv__src); \
5093                 DUK_TVAL_DECREF((thr), &tv__tmp);  /* side effects */ \
5094         } while (0)
5095
5096 /* Faster alternative: avoid making a temporary copy of tvptr_dst and use
5097  * fast incref/decref macros.
5098  */
5099 #define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \
5100                 duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
5101                 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
5102                 DUK_TVAL_INCREF_FAST((thr), tv__src); \
5103                 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \
5104                         h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
5105                         DUK_ASSERT(h__obj != NULL); \
5106                         DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
5107                         DUK_HEAPHDR_DECREF_FAST((thr), h__obj);  /* side effects */ \
5108                 } else { \
5109                         DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
5110                 } \
5111         } while (0)
5112
5113 /* XXX: no optimized variants yet */
5114 #define DUK_TVAL_SET_UNDEFINED_UPDREF         DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
5115 #define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ    DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0
5116 #define DUK_TVAL_SET_UNUSED_UPDREF            DUK_TVAL_SET_UNUSED_UPDREF_ALT0
5117 #define DUK_TVAL_SET_NULL_UPDREF              DUK_TVAL_SET_NULL_UPDREF_ALT0
5118 #define DUK_TVAL_SET_BOOLEAN_UPDREF           DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
5119 #define DUK_TVAL_SET_NUMBER_UPDREF            DUK_TVAL_SET_NUMBER_UPDREF_ALT0
5120 #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF    DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
5121 #define DUK_TVAL_SET_DOUBLE_UPDREF            DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
5122 #define DUK_TVAL_SET_NAN_UPDREF               DUK_TVAL_SET_NAN_UPDREF_ALT0
5123 #if defined(DUK_USE_FASTINT)
5124 #define DUK_TVAL_SET_I48_UPDREF               DUK_TVAL_SET_I48_UPDREF_ALT0
5125 #define DUK_TVAL_SET_I32_UPDREF               DUK_TVAL_SET_I32_UPDREF_ALT0
5126 #define DUK_TVAL_SET_U32_UPDREF               DUK_TVAL_SET_U32_UPDREF_ALT0
5127 #else
5128 #define DUK_TVAL_SET_I48_UPDREF               DUK_TVAL_SET_DOUBLE_CAST_UPDREF  /* XXX: fast int-to-double */
5129 #define DUK_TVAL_SET_I32_UPDREF               DUK_TVAL_SET_DOUBLE_CAST_UPDREF
5130 #define DUK_TVAL_SET_U32_UPDREF               DUK_TVAL_SET_DOUBLE_CAST_UPDREF
5131 #endif  /* DUK_USE_FASTINT */
5132 #define DUK_TVAL_SET_FASTINT_UPDREF           DUK_TVAL_SET_I48_UPDREF  /* convenience */
5133 #define DUK_TVAL_SET_LIGHTFUNC_UPDREF         DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
5134 #define DUK_TVAL_SET_STRING_UPDREF            DUK_TVAL_SET_STRING_UPDREF_ALT0
5135 #define DUK_TVAL_SET_OBJECT_UPDREF            DUK_TVAL_SET_OBJECT_UPDREF_ALT0
5136 #define DUK_TVAL_SET_BUFFER_UPDREF            DUK_TVAL_SET_BUFFER_UPDREF_ALT0
5137 #define DUK_TVAL_SET_POINTER_UPDREF           DUK_TVAL_SET_POINTER_UPDREF_ALT0
5138
5139 #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
5140 /* Optimized for speed. */
5141 #define DUK_TVAL_SET_TVAL_UPDREF              DUK_TVAL_SET_TVAL_UPDREF_ALT1
5142 #define DUK_TVAL_SET_TVAL_UPDREF_FAST         DUK_TVAL_SET_TVAL_UPDREF_ALT1
5143 #define DUK_TVAL_SET_TVAL_UPDREF_SLOW         DUK_TVAL_SET_TVAL_UPDREF_ALT0
5144 #else
5145 /* Optimized for size. */
5146 #define DUK_TVAL_SET_TVAL_UPDREF              DUK_TVAL_SET_TVAL_UPDREF_ALT0
5147 #define DUK_TVAL_SET_TVAL_UPDREF_FAST         DUK_TVAL_SET_TVAL_UPDREF_ALT0
5148 #define DUK_TVAL_SET_TVAL_UPDREF_SLOW         DUK_TVAL_SET_TVAL_UPDREF_ALT0
5149 #endif
5150
5151 #else  /* DUK_USE_REFERENCE_COUNTING */
5152
5153 #define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)     0
5154 #define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h)   0
5155
5156 #define DUK_TVAL_INCREF_FAST(thr,v)            do {} while (0) /* nop */
5157 #define DUK_TVAL_DECREF_FAST(thr,v)            do {} while (0) /* nop */
5158 #define DUK_TVAL_DECREF_NORZ_FAST(thr,v)       do {} while (0) /* nop */
5159 #define DUK_TVAL_INCREF_SLOW(thr,v)            do {} while (0) /* nop */
5160 #define DUK_TVAL_DECREF_SLOW(thr,v)            do {} while (0) /* nop */
5161 #define DUK_TVAL_DECREF_NORZ_SLOW(thr,v)       do {} while (0) /* nop */
5162 #define DUK_TVAL_INCREF(thr,v)                 do {} while (0) /* nop */
5163 #define DUK_TVAL_DECREF(thr,v)                 do {} while (0) /* nop */
5164 #define DUK_TVAL_DECREF_NORZ(thr,v)            do {} while (0) /* nop */
5165 #define DUK_HEAPHDR_INCREF_FAST(thr,h)         do {} while (0) /* nop */
5166 #define DUK_HEAPHDR_DECREF_FAST(thr,h)         do {} while (0) /* nop */
5167 #define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h)    do {} while (0) /* nop */
5168 #define DUK_HEAPHDR_INCREF_SLOW(thr,h)         do {} while (0) /* nop */
5169 #define DUK_HEAPHDR_DECREF_SLOW(thr,h)         do {} while (0) /* nop */
5170 #define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h)    do {} while (0) /* nop */
5171 #define DUK_HEAPHDR_INCREF(thr,h)              do {} while (0) /* nop */
5172 #define DUK_HEAPHDR_DECREF(thr,h)              do {} while (0) /* nop */
5173 #define DUK_HEAPHDR_DECREF_NORZ(thr,h)         do {} while (0) /* nop */
5174 #define DUK_HSTRING_INCREF_FAST(thr,h)         do {} while (0) /* nop */
5175 #define DUK_HSTRING_DECREF_FAST(thr,h)         do {} while (0) /* nop */
5176 #define DUK_HSTRING_DECREF_NORZ_FAST(thr,h)    do {} while (0) /* nop */
5177 #define DUK_HSTRING_INCREF_SLOW(thr,h)         do {} while (0) /* nop */
5178 #define DUK_HSTRING_DECREF_SLOW(thr,h)         do {} while (0) /* nop */
5179 #define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h)    do {} while (0) /* nop */
5180 #define DUK_HSTRING_INCREF(thr,h)              do {} while (0) /* nop */
5181 #define DUK_HSTRING_DECREF(thr,h)              do {} while (0) /* nop */
5182 #define DUK_HSTRING_DECREF_NORZ(thr,h)         do {} while (0) /* nop */
5183 #define DUK_HOBJECT_INCREF_FAST(thr,h)         do {} while (0) /* nop */
5184 #define DUK_HOBJECT_DECREF_FAST(thr,h)         do {} while (0) /* nop */
5185 #define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h)    do {} while (0) /* nop */
5186 #define DUK_HOBJECT_INCREF_SLOW(thr,h)         do {} while (0) /* nop */
5187 #define DUK_HOBJECT_DECREF_SLOW(thr,h)         do {} while (0) /* nop */
5188 #define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h)    do {} while (0) /* nop */
5189 #define DUK_HOBJECT_INCREF(thr,h)              do {} while (0) /* nop */
5190 #define DUK_HOBJECT_DECREF(thr,h)              do {} while (0) /* nop */
5191 #define DUK_HOBJECT_DECREF_NORZ(thr,h)         do {} while (0) /* nop */
5192 #define DUK_HBUFFER_INCREF_FAST(thr,h)         do {} while (0) /* nop */
5193 #define DUK_HBUFFER_DECREF_FAST(thr,h)         do {} while (0) /* nop */
5194 #define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h)    do {} while (0) /* nop */
5195 #define DUK_HBUFFER_INCREF_SLOW(thr,h)         do {} while (0) /* nop */
5196 #define DUK_HBUFFER_DECREF_SLOW(thr,h)         do {} while (0) /* nop */
5197 #define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h)    do {} while (0) /* nop */
5198 #define DUK_HBUFFER_INCREF(thr,h)              do {} while (0) /* nop */
5199 #define DUK_HBUFFER_DECREF(thr,h)              do {} while (0) /* nop */
5200 #define DUK_HBUFFER_DECREF_NORZ(thr,h)         do {} while (0) /* nop */
5201
5202 #define DUK_HCOMPFUNC_INCREF(thr,h)            do {} while (0) /* nop */
5203 #define DUK_HCOMPFUNC_DECREF(thr,h)            do {} while (0) /* nop */
5204 #define DUK_HCOMPFUNC_DECREF_NORZ(thr,h)       do {} while (0) /* nop */
5205 #define DUK_HNATFUNC_INCREF(thr,h)             do {} while (0) /* nop */
5206 #define DUK_HNATFUNC_DECREF(thr,h)             do {} while (0) /* nop */
5207 #define DUK_HNATFUNC_DECREF_NORZ(thr,h)        do {} while (0) /* nop */
5208 #define DUK_HBUFOBJ_INCREF(thr,h)              do {} while (0) /* nop */
5209 #define DUK_HBUFOBJ_DECREF(thr,h)              do {} while (0) /* nop */
5210 #define DUK_HBUFOBJ_DECREF_NORZ(thr,h)         do {} while (0) /* nop */
5211 #define DUK_HTHREAD_INCREF(thr,h)              do {} while (0) /* nop */
5212 #define DUK_HTHREAD_DECREF(thr,h)              do {} while (0) /* nop */
5213 #define DUK_HTHREAD_DECREF_NORZ(thr,h)         do {} while (0) /* nop */
5214 #define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h)    do {} while (0) /* nop */
5215 #define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h)    do {} while (0) /* nop */
5216 #define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h)  do {} while (0) /* nop */
5217 #define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h)    do {} while (0) /* nop */
5218 #define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h)    do {} while (0) /* nop */
5219 #define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h)  do {} while (0) /* nop */
5220
5221 #define DUK_REFZERO_CHECK_FAST(thr)            do {} while (0) /* nop */
5222 #define DUK_REFZERO_CHECK_SLOW(thr)            do {} while (0) /* nop */
5223
5224 #define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
5225                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5226                 DUK_TVAL_SET_UNDEFINED(tv__dst); \
5227                 DUK_UNREF((thr)); \
5228         } while (0)
5229
5230 #define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
5231                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5232                 DUK_TVAL_SET_UNUSED(tv__dst); \
5233                 DUK_UNREF((thr)); \
5234         } while (0)
5235
5236 #define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
5237                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5238                 DUK_TVAL_SET_NULL(tv__dst); \
5239                 DUK_UNREF((thr)); \
5240         } while (0)
5241
5242 #define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5243                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5244                 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
5245                 DUK_UNREF((thr)); \
5246         } while (0)
5247
5248 #define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5249                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5250                 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
5251                 DUK_UNREF((thr)); \
5252         } while (0)
5253 #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5254                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5255                 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
5256                 DUK_UNREF((thr)); \
5257         } while (0)
5258 #define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5259                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5260                 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
5261                 DUK_UNREF((thr)); \
5262         } while (0)
5263 #define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
5264                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5265                 DUK_TVAL_SET_NAN(tv__dst); \
5266                 DUK_UNREF((thr)); \
5267         } while (0)
5268 #if defined(DUK_USE_FASTINT)
5269 #define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5270                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5271                 DUK_TVAL_SET_I48(tv__dst, (newval)); \
5272                 DUK_UNREF((thr)); \
5273         } while (0)
5274 #define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5275                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5276                 DUK_TVAL_SET_I32(tv__dst, (newval)); \
5277                 DUK_UNREF((thr)); \
5278         } while (0)
5279 #define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5280                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5281                 DUK_TVAL_SET_U32(tv__dst, (newval)); \
5282                 DUK_UNREF((thr)); \
5283         } while (0)
5284 #else
5285 #define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
5286         DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
5287 #endif  /* DUK_USE_FASTINT */
5288
5289 #define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
5290                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5291                 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
5292                 DUK_UNREF((thr)); \
5293         } while (0)
5294
5295 #define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5296                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5297                 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
5298                 DUK_UNREF((thr)); \
5299         } while (0)
5300
5301 #define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5302                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5303                 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
5304                 DUK_UNREF((thr)); \
5305         } while (0)
5306
5307 #define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5308                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5309                 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
5310                 DUK_UNREF((thr)); \
5311         } while (0)
5312
5313 #define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
5314                 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
5315                 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
5316                 DUK_UNREF((thr)); \
5317         } while (0)
5318
5319 #define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
5320                 duk_tval *tv__dst, *tv__src; \
5321                 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
5322                 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
5323                 DUK_UNREF((thr)); \
5324         } while (0)
5325
5326 #define DUK_TVAL_SET_UNDEFINED_UPDREF         DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
5327 #define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ    DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
5328 #define DUK_TVAL_SET_UNUSED_UPDREF            DUK_TVAL_SET_UNUSED_UPDREF_ALT0
5329 #define DUK_TVAL_SET_NULL_UPDREF              DUK_TVAL_SET_NULL_UPDREF_ALT0
5330 #define DUK_TVAL_SET_BOOLEAN_UPDREF           DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
5331 #define DUK_TVAL_SET_NUMBER_UPDREF            DUK_TVAL_SET_NUMBER_UPDREF_ALT0
5332 #define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF    DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
5333 #define DUK_TVAL_SET_DOUBLE_UPDREF            DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
5334 #define DUK_TVAL_SET_NAN_UPDREF               DUK_TVAL_SET_NAN_UPDREF_ALT0
5335 #if defined(DUK_USE_FASTINT)
5336 #define DUK_TVAL_SET_I48_UPDREF               DUK_TVAL_SET_I48_UPDREF_ALT0
5337 #define DUK_TVAL_SET_I32_UPDREF               DUK_TVAL_SET_I32_UPDREF_ALT0
5338 #define DUK_TVAL_SET_U32_UPDREF               DUK_TVAL_SET_U32_UPDREF_ALT0
5339 #else
5340 #define DUK_TVAL_SET_I48_UPDREF               DUK_TVAL_SET_DOUBLE_CAST_UPDREF  /* XXX: fast-int-to-double */
5341 #define DUK_TVAL_SET_I32_UPDREF               DUK_TVAL_SET_DOUBLE_CAST_UPDREF
5342 #define DUK_TVAL_SET_U32_UPDREF               DUK_TVAL_SET_DOUBLE_CAST_UPDREF
5343 #endif  /* DUK_USE_FASTINT */
5344 #define DUK_TVAL_SET_FASTINT_UPDREF           DUK_TVAL_SET_I48_UPDREF  /* convenience */
5345 #define DUK_TVAL_SET_LIGHTFUNC_UPDREF         DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
5346 #define DUK_TVAL_SET_STRING_UPDREF            DUK_TVAL_SET_STRING_UPDREF_ALT0
5347 #define DUK_TVAL_SET_OBJECT_UPDREF            DUK_TVAL_SET_OBJECT_UPDREF_ALT0
5348 #define DUK_TVAL_SET_BUFFER_UPDREF            DUK_TVAL_SET_BUFFER_UPDREF_ALT0
5349 #define DUK_TVAL_SET_POINTER_UPDREF           DUK_TVAL_SET_POINTER_UPDREF_ALT0
5350
5351 #define DUK_TVAL_SET_TVAL_UPDREF              DUK_TVAL_SET_TVAL_UPDREF_ALT0
5352 #define DUK_TVAL_SET_TVAL_UPDREF_FAST         DUK_TVAL_SET_TVAL_UPDREF_ALT0
5353 #define DUK_TVAL_SET_TVAL_UPDREF_SLOW         DUK_TVAL_SET_TVAL_UPDREF_ALT0
5354
5355 #endif  /* DUK_USE_REFERENCE_COUNTING */
5356
5357 /*
5358  *  Some convenience macros that don't have optimized implementations now.
5359  */
5360
5361 #define DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr,tv_dst,tv_src) do { \
5362                 duk_hthread *duk__thr = (thr); \
5363                 duk_tval *duk__dst = (tv_dst); \
5364                 duk_tval *duk__src = (tv_src); \
5365                 DUK_UNREF(duk__thr); \
5366                 DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
5367                 DUK_TVAL_SET_TVAL(duk__dst, duk__src); \
5368                 DUK_TVAL_INCREF(thr, duk__dst); \
5369         } while (0)
5370
5371 #define DUK_TVAL_SET_U32_UPDREF_NORZ(thr,tv_dst,val) do { \
5372                 duk_hthread *duk__thr = (thr); \
5373                 duk_tval *duk__dst = (tv_dst); \
5374                 duk_uint32_t duk__val = (duk_uint32_t) (val); \
5375                 DUK_UNREF(duk__thr); \
5376                 DUK_TVAL_DECREF_NORZ(thr, duk__dst); \
5377                 DUK_TVAL_SET_U32(duk__dst, duk__val); \
5378         } while (0)
5379
5380 /*
5381  *  Prototypes
5382  */
5383
5384 #if defined(DUK_USE_REFERENCE_COUNTING)
5385 #if defined(DUK_USE_FINALIZER_SUPPORT)
5386 DUK_INTERNAL_DECL void duk_refzero_check_slow(duk_hthread *thr);
5387 DUK_INTERNAL_DECL void duk_refzero_check_fast(duk_hthread *thr);
5388 #endif
5389 DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr);
5390 DUK_INTERNAL_DECL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h);
5391 #if 0  /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */
5392 DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h);
5393 DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h);
5394 DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h);
5395 DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h);
5396 DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h);
5397 DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h);
5398 #endif
5399 DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
5400 DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h);
5401 #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
5402 DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h);  /* no 'norz' variant */
5403 DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h);  /* no 'norz' variant */
5404 DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h);
5405 DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h);
5406 #else
5407 DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
5408 DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
5409 DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv);
5410 DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
5411 DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
5412 DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h);
5413 #endif
5414 #else  /* DUK_USE_REFERENCE_COUNTING */
5415 /* no refcounting */
5416 #endif  /* DUK_USE_REFERENCE_COUNTING */
5417
5418 #endif  /* DUK_REFCOUNT_H_INCLUDED */
5419 /* #include duk_api_internal.h */
5420 #line 1 "duk_api_internal.h"
5421 /*
5422  *  Internal API calls which have (stack and other) semantics similar
5423  *  to the public API.
5424  */
5425
5426 #if !defined(DUK_API_INTERNAL_H_INCLUDED)
5427 #define DUK_API_INTERNAL_H_INCLUDED
5428
5429 #define DUK_INTERNAL_SYMBOL(x)     ("\x82" x)
5430
5431 /* duk_push_sprintf constants */
5432 #define DUK_PUSH_SPRINTF_INITIAL_SIZE  256L
5433 #define DUK_PUSH_SPRINTF_SANITY_LIMIT  (1L * 1024L * 1024L * 1024L)
5434
5435 /* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not
5436  * blamed as source of error for error fileName / lineNumber.
5437  */
5438 #define DUK_ERRCODE_FLAG_NOBLAME_FILELINE  (1L << 24)
5439
5440 /* Current convention is to use duk_size_t for value stack sizes and global indices,
5441  * and duk_idx_t for local frame indices.
5442  */
5443 DUK_INTERNAL_DECL void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes);
5444 DUK_INTERNAL_DECL duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes);
5445 DUK_INTERNAL_DECL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug);
5446
5447 DUK_INTERNAL_DECL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count);
5448
5449 DUK_INTERNAL_DECL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count);
5450
5451 DUK_INTERNAL_DECL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx);
5452 DUK_INTERNAL_DECL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start);
5453
5454 DUK_INTERNAL_DECL void duk_dup_0(duk_hthread *thr);
5455 DUK_INTERNAL_DECL void duk_dup_1(duk_hthread *thr);
5456 DUK_INTERNAL_DECL void duk_dup_2(duk_hthread *thr);
5457 /* duk_dup_m1() would be same as duk_dup_top() */
5458 DUK_INTERNAL_DECL void duk_dup_m2(duk_hthread *thr);
5459 DUK_INTERNAL_DECL void duk_dup_m3(duk_hthread *thr);
5460 DUK_INTERNAL_DECL void duk_dup_m4(duk_hthread *thr);
5461
5462 DUK_INTERNAL_DECL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx);
5463 DUK_INTERNAL_DECL void duk_remove_m2(duk_hthread *thr);
5464 DUK_INTERNAL_DECL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
5465 DUK_INTERNAL_DECL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
5466
5467 DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv);
5468 DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv);
5469
5470 #if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
5471 DUK_INTERNAL_DECL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx);
5472 #endif
5473 DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx);
5474
5475 DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx);
5476 DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx);
5477 DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx);
5478 DUK_INTERNAL_DECL void duk_push_tval(duk_hthread *thr, duk_tval *tv);
5479
5480 /* Push the current 'this' binding; throw TypeError if binding is not object
5481  * coercible (CheckObjectCoercible).
5482  */
5483 DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_hthread *thr);
5484
5485 /* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
5486 DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr);
5487
5488 /* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
5489 DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr);
5490
5491 DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i);
5492
5493 /* Get a borrowed duk_tval pointer to the current 'this' binding.  Caller must
5494  * make sure there's an active callstack entry.  Note that the returned pointer
5495  * is unstable with regards to side effects.
5496  */
5497 DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr);
5498
5499 /* XXX: add fastint support? */
5500 #define duk_push_u64(thr,val) \
5501         duk_push_number((thr), (duk_double_t) (val))
5502 #define duk_push_i64(thr,val) \
5503         duk_push_number((thr), (duk_double_t) (val))
5504
5505 /* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
5506 #define duk_push_u32(thr,val) \
5507         duk_push_uint((thr), (duk_uint_t) (val))
5508 #define duk_push_i32(thr,val) \
5509         duk_push_int((thr), (duk_int_t) (val))
5510
5511 /* sometimes stack and array indices need to go on the stack */
5512 #define duk_push_idx(thr,val) \
5513         duk_push_int((thr), (duk_int_t) (val))
5514 #define duk_push_uarridx(thr,val) \
5515         duk_push_uint((thr), (duk_uint_t) (val))
5516 #define duk_push_size_t(thr,val) \
5517         duk_push_uint((thr), (duk_uint_t) (val))  /* XXX: assumed to fit for now */
5518
5519 DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
5520
5521 DUK_INTERNAL_DECL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv);
5522
5523 DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx);
5524 DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
5525 DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
5526 DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx);
5527 DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx);
5528 DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx);
5529 DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx);
5530 DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx);
5531
5532 DUK_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);
5533
5534 DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
5535
5536 DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
5537 DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
5538 DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask);
5539 #define duk_require_hobject_promote_lfunc(thr,idx) \
5540         duk_require_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
5541 #define duk_get_hobject_promote_lfunc(thr,idx) \
5542         duk_get_hobject_promote_mask((thr), (idx), DUK_TYPE_MASK_LIGHTFUNC)
5543
5544 #if 0  /*unused*/
5545 DUK_INTERNAL_DECL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx);
5546 #endif
5547
5548 DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx);
5549 DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx);
5550 DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx);
5551 DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx);
5552 DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx);
5553
5554 DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv);
5555
5556 DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx);
5557 DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_hthread *thr);
5558 DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx);
5559
5560 DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx);
5561
5562 DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_hthread *thr);
5563 DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_hthread *thr);
5564
5565 DUK_INTERNAL_DECL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr);
5566
5567 #if defined(DUK_USE_DEBUGGER_SUPPORT)  /* only needed by debugger for now */
5568 DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx);
5569 #endif
5570 DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects);
5571
5572 DUK_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 */
5573 DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
5574 DUK_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);
5575 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
5576 DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx);
5577 #endif
5578 DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx);
5579
5580 DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx);
5581 DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx);
5582 DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len);
5583 DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx);
5584 DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx);
5585 DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx);
5586 DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx);
5587 DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx);
5588 DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx);
5589
5590 DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum);
5591
5592 DUK_INTERNAL_DECL void duk_push_hstring(duk_hthread *thr, duk_hstring *h);
5593 DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx);
5594 DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_hthread *thr);
5595 DUK_INTERNAL_DECL void duk_push_hobject(duk_hthread *thr, duk_hobject *h);
5596 DUK_INTERNAL_DECL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h);
5597 #define duk_push_hthread(thr,h) \
5598         duk_push_hobject((thr), (duk_hobject *) (h))
5599 #define duk_push_hnatfunc(thr,h) \
5600         duk_push_hobject((thr), (duk_hobject *) (h))
5601 DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx);
5602 DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
5603 DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
5604 DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr);
5605 DUK_INTERNAL_DECL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr);
5606 DUK_INTERNAL_DECL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
5607 DUK_INTERNAL_DECL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs);
5608
5609 /* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with
5610  * duk_push_hobject() etc which don't create a new value.
5611  */
5612 DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_hthread *thr);
5613 DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size);
5614 DUK_INTERNAL_DECL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size);
5615
5616 DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz);
5617 DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags);
5618 DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv);
5619 DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv);
5620 #if 0  /* not used yet */
5621 DUK_INTERNAL_DECL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h);
5622 #endif
5623 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
5624 DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
5625 #endif
5626
5627 DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len);
5628 DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len);
5629
5630 DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx);
5631 DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv);
5632 DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv);
5633
5634 /* The duk_xxx_prop_stridx_short() variants expect their arguments to be short
5635  * enough to be packed into a single 32-bit integer argument.  Argument limits
5636  * vary per call; typically 16 bits are assigned to the signed value stack index
5637  * and the stridx.  In practice these work well for footprint with constant
5638  * arguments and such call sites are also easiest to verify to be correct.
5639  */
5640
5641 DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx);     /* [] -> [val] */
5642 DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5643 #define duk_get_prop_stridx_short(thr,obj_idx,stridx) \
5644         (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
5645          DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
5646          duk_get_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5647 DUK_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);  /* [] -> [] */
5648
5649 DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx);     /* [val] -> [] */
5650 DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5651 #define duk_put_prop_stridx_short(thr,obj_idx,stridx) \
5652         (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
5653          DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
5654          duk_put_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5655
5656 DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx);     /* [] -> [] */
5657 #if 0  /* Too few call sites to be useful. */
5658 DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5659 #define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
5660         (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
5661          DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
5662          duk_del_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5663 #endif
5664 #define duk_del_prop_stridx_short(thr,obj_idx,stridx) \
5665         duk_del_prop_stridx((thr), (obj_idx), (stridx))
5666
5667 DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx);     /* [] -> [] */
5668 #if 0  /* Too few call sites to be useful. */
5669 DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5670 #define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
5671         (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
5672          DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
5673          duk_has_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
5674 #endif
5675 #define duk_has_prop_stridx_short(thr,obj_idx,stridx) \
5676         duk_has_prop_stridx((thr), (obj_idx), (stridx))
5677
5678 DUK_INTERNAL_DECL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags);  /* [key val] -> [] */
5679
5680 DUK_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] -> [] */
5681
5682 /* XXX: Because stridx and desc_flags have a limited range, this call could
5683  * always pack stridx and desc_flags into a single argument.
5684  */
5685 DUK_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] -> [] */
5686 DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args);
5687 #define duk_xdef_prop_stridx_short(thr,obj_idx,stridx,desc_flags) \
5688         (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \
5689          DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
5690          DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \
5691          duk_xdef_prop_stridx_short_raw((thr), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags)))
5692
5693 #define duk_xdef_prop_wec(thr,obj_idx) \
5694         duk_xdef_prop((thr), (obj_idx), DUK_PROPDESC_FLAGS_WEC)
5695 #define duk_xdef_prop_index_wec(thr,obj_idx,arr_idx) \
5696         duk_xdef_prop_index((thr), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC)
5697 #define duk_xdef_prop_stridx_wec(thr,obj_idx,stridx) \
5698         duk_xdef_prop_stridx((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
5699 #define duk_xdef_prop_stridx_short_wec(thr,obj_idx,stridx) \
5700         duk_xdef_prop_stridx_short((thr), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
5701
5702 #if 0  /*unused*/
5703 DUK_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);  /* [] -> [] */
5704 #endif
5705
5706 DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx);  /* [] -> [] */
5707
5708 DUK_INTERNAL_DECL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx);
5709
5710 DUK_INTERNAL_DECL void duk_pack(duk_hthread *thr, duk_idx_t count);
5711 DUK_INTERNAL_DECL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx);
5712 #if 0
5713 DUK_INTERNAL_DECL void duk_unpack(duk_hthread *thr);
5714 #endif
5715
5716 DUK_INTERNAL_DECL void duk_require_constructor_call(duk_hthread *thr);
5717 DUK_INTERNAL_DECL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx);
5718 DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h);
5719
5720 DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_hthread *thr);
5721
5722 DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top);
5723 DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr);
5724
5725 DUK_INTERNAL_DECL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count);
5726 DUK_INTERNAL_DECL void duk_pop_unsafe(duk_hthread *thr);
5727 DUK_INTERNAL_DECL void duk_pop_2_unsafe(duk_hthread *thr);
5728 DUK_INTERNAL_DECL void duk_pop_3_unsafe(duk_hthread *thr);
5729 DUK_INTERNAL_DECL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count);
5730 DUK_INTERNAL_DECL void duk_pop_nodecref_unsafe(duk_hthread *thr);
5731 DUK_INTERNAL_DECL void duk_pop_2_nodecref_unsafe(duk_hthread *thr);
5732 DUK_INTERNAL_DECL void duk_pop_3_nodecref_unsafe(duk_hthread *thr);
5733 DUK_INTERNAL_DECL void duk_pop_undefined(duk_hthread *thr);
5734
5735 DUK_INTERNAL_DECL void duk_compact_m1(duk_hthread *thr);
5736
5737 DUK_INTERNAL_DECL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze);
5738
5739 DUK_INTERNAL_DECL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx);
5740 DUK_INTERNAL_DECL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count);
5741
5742 DUK_INTERNAL_DECL void duk_concat_2(duk_hthread *thr);
5743
5744 DUK_INTERNAL_DECL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
5745
5746 #if defined(DUK_USE_SYMBOL_BUILTIN)
5747 DUK_INTERNAL_DECL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint);
5748 #endif
5749
5750 /* Raw internal valstack access macros: access is unsafe so call site
5751  * must have a guarantee that the index is valid.  When that is the case,
5752  * using these macro results in faster and smaller code than duk_get_tval().
5753  * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
5754  */
5755 #define DUK_ASSERT_VALID_NEGIDX(thr,idx) \
5756         (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
5757 #define DUK_ASSERT_VALID_POSIDX(thr,idx) \
5758         (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((thr), (idx))))
5759 #define DUK_GET_TVAL_NEGIDX(thr,idx) \
5760         (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_top + (idx))
5761 #define DUK_GET_TVAL_POSIDX(thr,idx) \
5762         (DUK_ASSERT_VALID_POSIDX((thr),(idx)), ((duk_hthread *) (thr))->valstack_bottom + (idx))
5763 #define DUK_GET_HOBJECT_NEGIDX(thr,idx) \
5764         (DUK_ASSERT_VALID_NEGIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_top + (idx)))
5765 #define DUK_GET_HOBJECT_POSIDX(thr,idx) \
5766         (DUK_ASSERT_VALID_POSIDX((thr),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (thr))->valstack_bottom + (idx)))
5767
5768 #define DUK_GET_THIS_TVAL_PTR(thr) \
5769         (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
5770          (thr)->valstack_bottom - 1)
5771
5772 DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr);
5773 DUK_INTERNAL_DECL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr);
5774 DUK_INTERNAL_DECL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr);
5775
5776 #endif  /* DUK_API_INTERNAL_H_INCLUDED */
5777 /* #include duk_hstring.h */
5778 #line 1 "duk_hstring.h"
5779 /*
5780  *  Heap string representation.
5781  *
5782  *  Strings are byte sequences ordinarily stored in extended UTF-8 format,
5783  *  allowing values larger than the official UTF-8 range (used internally)
5784  *  and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format).
5785  *  Strings may also be invalid UTF-8 altogether which is the case e.g. with
5786  *  strings used as internal property names and raw buffers converted to
5787  *  strings.  In such cases the 'clen' field contains an inaccurate value.
5788  *
5789  *  ECMAScript requires support for 32-bit long strings.  However, since each
5790  *  16-bit codepoint can take 3 bytes in CESU-8, this representation can only
5791  *  support about 1.4G codepoint long strings in extreme cases.  This is not
5792  *  really a practical issue.
5793  */
5794
5795 #if !defined(DUK_HSTRING_H_INCLUDED)
5796 #define DUK_HSTRING_H_INCLUDED
5797
5798 /* Impose a maximum string length for now.  Restricted artificially to
5799  * ensure adding a heap header length won't overflow size_t.  The limit
5800  * should be synchronized with DUK_HBUFFER_MAX_BYTELEN.
5801  *
5802  * E5.1 makes provisions to support strings longer than 4G characters.
5803  * This limit should be eliminated on 64-bit platforms (and increased
5804  * closer to maximum support on 32-bit platforms).
5805  */
5806
5807 #if defined(DUK_USE_STRLEN16)
5808 #define DUK_HSTRING_MAX_BYTELEN                     (0x0000ffffUL)
5809 #else
5810 #define DUK_HSTRING_MAX_BYTELEN                     (0x7fffffffUL)
5811 #endif
5812
5813 /* XXX: could add flags for "is valid CESU-8" (ECMAScript compatible strings),
5814  * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not,
5815  * regexp bytecode is), and "contains non-BMP characters".  These are not
5816  * needed right now.
5817  */
5818
5819 /* With lowmem builds the high 16 bits of duk_heaphdr are used for other
5820  * purposes, so this leaves 7 duk_heaphdr flags and 9 duk_hstring flags.
5821  */
5822 #define DUK_HSTRING_FLAG_ASCII                      DUK_HEAPHDR_USER_FLAG(0)  /* string is ASCII, clen == blen */
5823 #define DUK_HSTRING_FLAG_ARRIDX                     DUK_HEAPHDR_USER_FLAG(1)  /* string is a valid array index */
5824 #define DUK_HSTRING_FLAG_SYMBOL                     DUK_HEAPHDR_USER_FLAG(2)  /* string is a symbol (invalid utf-8) */
5825 #define DUK_HSTRING_FLAG_HIDDEN                     DUK_HEAPHDR_USER_FLAG(3)  /* string is a hidden symbol (implies symbol, Duktape 1.x internal string) */
5826 #define DUK_HSTRING_FLAG_RESERVED_WORD              DUK_HEAPHDR_USER_FLAG(4)  /* string is a reserved word (non-strict) */
5827 #define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD       DUK_HEAPHDR_USER_FLAG(5)  /* string is a reserved word (strict) */
5828 #define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS          DUK_HEAPHDR_USER_FLAG(6)  /* string is 'eval' or 'arguments' */
5829 #define DUK_HSTRING_FLAG_EXTDATA                    DUK_HEAPHDR_USER_FLAG(7)  /* string data is external (duk_hstring_external) */
5830 #define DUK_HSTRING_FLAG_PINNED_LITERAL             DUK_HEAPHDR_USER_FLAG(8)  /* string is a literal, and pinned */
5831
5832 #define DUK_HSTRING_HAS_ASCII(x)                    DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5833 #define DUK_HSTRING_HAS_ARRIDX(x)                   DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5834 #define DUK_HSTRING_HAS_SYMBOL(x)                   DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5835 #define DUK_HSTRING_HAS_HIDDEN(x)                   DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5836 #define DUK_HSTRING_HAS_RESERVED_WORD(x)            DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5837 #define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x)     DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5838 #define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x)        DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5839 #define DUK_HSTRING_HAS_EXTDATA(x)                  DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5840 #define DUK_HSTRING_HAS_PINNED_LITERAL(x)           DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
5841
5842 #define DUK_HSTRING_SET_ASCII(x)                    DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5843 #define DUK_HSTRING_SET_ARRIDX(x)                   DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5844 #define DUK_HSTRING_SET_SYMBOL(x)                   DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5845 #define DUK_HSTRING_SET_HIDDEN(x)                   DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5846 #define DUK_HSTRING_SET_RESERVED_WORD(x)            DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5847 #define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x)     DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5848 #define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x)        DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5849 #define DUK_HSTRING_SET_EXTDATA(x)                  DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5850 #define DUK_HSTRING_SET_PINNED_LITERAL(x)           DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
5851
5852 #define DUK_HSTRING_CLEAR_ASCII(x)                  DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5853 #define DUK_HSTRING_CLEAR_ARRIDX(x)                 DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5854 #define DUK_HSTRING_CLEAR_SYMBOL(x)                 DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5855 #define DUK_HSTRING_CLEAR_HIDDEN(x)                 DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5856 #define DUK_HSTRING_CLEAR_RESERVED_WORD(x)          DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5857 #define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x)   DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5858 #define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x)      DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5859 #define DUK_HSTRING_CLEAR_EXTDATA(x)                DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5860 #define DUK_HSTRING_CLEAR_PINNED_LITERAL(x)         DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_PINNED_LITERAL)
5861
5862 #if 0  /* Slightly smaller code without explicit flag, but explicit flag
5863         * is very useful when 'clen' is dropped.
5864         */
5865 #define DUK_HSTRING_IS_ASCII(x)                     (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x)))
5866 #endif
5867 #define DUK_HSTRING_IS_ASCII(x)                     DUK_HSTRING_HAS_ASCII((x))  /* lazily set! */
5868 #define DUK_HSTRING_IS_EMPTY(x)                     (DUK_HSTRING_GET_BYTELEN((x)) == 0)
5869
5870 #if defined(DUK_USE_STRHASH16)
5871 #define DUK_HSTRING_GET_HASH(x)                     ((x)->hdr.h_flags >> 16)
5872 #define DUK_HSTRING_SET_HASH(x,v) do { \
5873                 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \
5874         } while (0)
5875 #else
5876 #define DUK_HSTRING_GET_HASH(x)                     ((x)->hash)
5877 #define DUK_HSTRING_SET_HASH(x,v) do { \
5878                 (x)->hash = (v); \
5879         } while (0)
5880 #endif
5881
5882 #if defined(DUK_USE_STRLEN16)
5883 #define DUK_HSTRING_GET_BYTELEN(x)                  ((x)->hdr.h_strextra16)
5884 #define DUK_HSTRING_SET_BYTELEN(x,v) do { \
5885                 (x)->hdr.h_strextra16 = (v); \
5886         } while (0)
5887 #if defined(DUK_USE_HSTRING_CLEN)
5888 #define DUK_HSTRING_GET_CHARLEN(x)                  duk_hstring_get_charlen((x))
5889 #define DUK_HSTRING_SET_CHARLEN(x,v) do { \
5890                 (x)->clen16 = (v); \
5891         } while (0)
5892 #else
5893 #define DUK_HSTRING_GET_CHARLEN(x)                  duk_hstring_get_charlen((x))
5894 #define DUK_HSTRING_SET_CHARLEN(x,v) do { \
5895                 DUK_ASSERT(0);  /* should never be called */ \
5896         } while (0)
5897 #endif
5898 #else
5899 #define DUK_HSTRING_GET_BYTELEN(x)                  ((x)->blen)
5900 #define DUK_HSTRING_SET_BYTELEN(x,v) do { \
5901                 (x)->blen = (v); \
5902         } while (0)
5903 #define DUK_HSTRING_GET_CHARLEN(x)                  duk_hstring_get_charlen((x))
5904 #define DUK_HSTRING_SET_CHARLEN(x,v) do { \
5905                 (x)->clen = (v); \
5906         } while (0)
5907 #endif
5908
5909 #if defined(DUK_USE_HSTRING_EXTDATA)
5910 #define DUK_HSTRING_GET_EXTDATA(x) \
5911         ((x)->extdata)
5912 #define DUK_HSTRING_GET_DATA(x) \
5913         (DUK_HSTRING_HAS_EXTDATA((x)) ? \
5914                 DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1)))
5915 #else
5916 #define DUK_HSTRING_GET_DATA(x) \
5917         ((const duk_uint8_t *) ((x) + 1))
5918 #endif
5919
5920 #define DUK_HSTRING_GET_DATA_END(x) \
5921         (DUK_HSTRING_GET_DATA((x)) + (x)->blen)
5922
5923 /* Marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest
5924  * valid).
5925  */
5926 #define DUK_HSTRING_NO_ARRAY_INDEX  (0xffffffffUL)
5927
5928 #if defined(DUK_USE_HSTRING_ARRIDX)
5929 #define DUK_HSTRING_GET_ARRIDX_FAST(h)  ((h)->arridx)
5930 #define DUK_HSTRING_GET_ARRIDX_SLOW(h)  ((h)->arridx)
5931 #else
5932 /* Get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
5933  * avoids helper call if string has no array index value.
5934  */
5935 #define DUK_HSTRING_GET_ARRIDX_FAST(h)  \
5936         (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_hstring_fast_known((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
5937
5938 /* Slower but more compact variant. */
5939 #define DUK_HSTRING_GET_ARRIDX_SLOW(h)  \
5940         (duk_js_to_arrayindex_hstring_fast((h)))
5941 #endif
5942
5943 /* XXX: these actually fit into duk_hstring */
5944 #define DUK_SYMBOL_TYPE_HIDDEN 0
5945 #define DUK_SYMBOL_TYPE_GLOBAL 1
5946 #define DUK_SYMBOL_TYPE_LOCAL 2
5947 #define DUK_SYMBOL_TYPE_WELLKNOWN 3
5948
5949 /*
5950  *  Misc
5951  */
5952
5953 struct duk_hstring {
5954         /* Smaller heaphdr than for other objects, because strings are held
5955          * in string intern table which requires no link pointers.  Much of
5956          * the 32-bit flags field is unused by flags, so we can stuff a 16-bit
5957          * field in there.
5958          */
5959         duk_heaphdr_string hdr;
5960
5961         /* String hash. */
5962 #if defined(DUK_USE_STRHASH16)
5963         /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */
5964 #else
5965         duk_uint32_t hash;
5966 #endif
5967
5968         /* Precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX). */
5969 #if defined(DUK_USE_HSTRING_ARRIDX)
5970         duk_uarridx_t arridx;
5971 #endif
5972
5973         /* Length in bytes (not counting NUL term). */
5974 #if defined(DUK_USE_STRLEN16)
5975         /* placed in duk_heaphdr_string */
5976 #else
5977         duk_uint32_t blen;
5978 #endif
5979
5980         /* Length in codepoints (must be E5 compatible). */
5981 #if defined(DUK_USE_STRLEN16)
5982 #if defined(DUK_USE_HSTRING_CLEN)
5983         duk_uint16_t clen16;
5984 #else
5985         /* computed live */
5986 #endif
5987 #else
5988         duk_uint32_t clen;
5989 #endif
5990
5991         /*
5992          *  String data of 'blen+1' bytes follows (+1 for NUL termination
5993          *  convenience for C API).  No alignment needs to be guaranteed
5994          *  for strings, but fields above should guarantee alignment-by-4
5995          *  (but not alignment-by-8).
5996          */
5997 };
5998
5999 /* The external string struct is defined even when the feature is inactive. */
6000 struct duk_hstring_external {
6001         duk_hstring str;
6002
6003         /*
6004          *  For an external string, the NUL-terminated string data is stored
6005          *  externally.  The user must guarantee that data behind this pointer
6006          *  doesn't change while it's used.
6007          */
6008
6009         const duk_uint8_t *extdata;
6010 };
6011
6012 /*
6013  *  Prototypes
6014  */
6015
6016 DUK_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);
6017 DUK_INTERNAL_DECL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr);
6018 DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
6019 #if !defined(DUK_USE_HSTRING_LAZY_CLEN)
6020 DUK_INTERNAL_DECL void duk_hstring_init_charlen(duk_hstring *h);
6021 #endif
6022
6023 #endif  /* DUK_HSTRING_H_INCLUDED */
6024 /* #include duk_hobject.h */
6025 #line 1 "duk_hobject.h"
6026 /*
6027  *  Heap object representation.
6028  *
6029  *  Heap objects are used for ECMAScript objects, arrays, and functions,
6030  *  but also for internal control like declarative and object environment
6031  *  records.  Compiled functions, native functions, and threads are also
6032  *  objects but with an extended C struct.
6033  *
6034  *  Objects provide the required ECMAScript semantics and exotic behaviors
6035  *  especially for property access.
6036  *
6037  *  Properties are stored in three conceptual parts:
6038  *
6039  *    1. A linear 'entry part' contains ordered key-value-attributes triples
6040  *       and is the main method of string properties.
6041  *
6042  *    2. An optional linear 'array part' is used for array objects to store a
6043  *       (dense) range of [0,N[ array indexed entries with default attributes
6044  *       (writable, enumerable, configurable).  If the array part would become
6045  *       sparse or non-default attributes are required, the array part is
6046  *       abandoned and moved to the 'entry part'.
6047  *
6048  *    3. An optional 'hash part' is used to optimize lookups of the entry
6049  *       part; it is used only for objects with sufficiently many properties
6050  *       and can be abandoned without loss of information.
6051  *
6052  *  These three conceptual parts are stored in a single memory allocated area.
6053  *  This minimizes memory allocation overhead but also means that all three
6054  *  parts are resized together, and makes property access a bit complicated.
6055  */
6056
6057 #if !defined(DUK_HOBJECT_H_INCLUDED)
6058 #define DUK_HOBJECT_H_INCLUDED
6059
6060 /* Object flags.  Make sure this stays in sync with debugger object
6061  * inspection code.
6062  */
6063
6064 /* XXX: some flags are object subtype specific (e.g. common to all function
6065  * subtypes, duk_harray, etc) and could be reused for different subtypes.
6066  */
6067 #define DUK_HOBJECT_FLAG_EXTENSIBLE            DUK_HEAPHDR_USER_FLAG(0)   /* object is extensible */
6068 #define DUK_HOBJECT_FLAG_CONSTRUCTABLE         DUK_HEAPHDR_USER_FLAG(1)   /* object is constructable */
6069 #define DUK_HOBJECT_FLAG_CALLABLE              DUK_HEAPHDR_USER_FLAG(2)   /* object is callable */
6070 #define DUK_HOBJECT_FLAG_BOUNDFUNC             DUK_HEAPHDR_USER_FLAG(3)   /* object established using Function.prototype.bind() */
6071 #define DUK_HOBJECT_FLAG_COMPFUNC              DUK_HEAPHDR_USER_FLAG(4)   /* object is a compiled function (duk_hcompfunc) */
6072 #define DUK_HOBJECT_FLAG_NATFUNC               DUK_HEAPHDR_USER_FLAG(5)   /* object is a native function (duk_hnatfunc) */
6073 #define DUK_HOBJECT_FLAG_BUFOBJ                DUK_HEAPHDR_USER_FLAG(6)   /* object is a buffer object (duk_hbufobj) (always exotic) */
6074 #define DUK_HOBJECT_FLAG_FASTREFS              DUK_HEAPHDR_USER_FLAG(7)   /* object has no fields needing DECREF/marking beyond base duk_hobject header */
6075 #define DUK_HOBJECT_FLAG_ARRAY_PART            DUK_HEAPHDR_USER_FLAG(8)   /* object has an array part (a_size may still be 0) */
6076 #define DUK_HOBJECT_FLAG_STRICT                DUK_HEAPHDR_USER_FLAG(9)   /* function: function object is strict */
6077 #define DUK_HOBJECT_FLAG_NOTAIL                DUK_HEAPHDR_USER_FLAG(10)  /* function: function must not be tail called */
6078 #define DUK_HOBJECT_FLAG_NEWENV                DUK_HEAPHDR_USER_FLAG(11)  /* function: create new environment when called (see duk_hcompfunc) */
6079 #define DUK_HOBJECT_FLAG_NAMEBINDING           DUK_HEAPHDR_USER_FLAG(12)  /* function: create binding for func name (function templates only, used for named function expressions) */
6080 #define DUK_HOBJECT_FLAG_CREATEARGS            DUK_HEAPHDR_USER_FLAG(13)  /* function: create an arguments object on function call */
6081 #define DUK_HOBJECT_FLAG_HAVE_FINALIZER        DUK_HEAPHDR_USER_FLAG(14)  /* object has a callable (own) finalizer property */
6082 #define DUK_HOBJECT_FLAG_EXOTIC_ARRAY          DUK_HEAPHDR_USER_FLAG(15)  /* 'Array' object, array length and index exotic behavior */
6083 #define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ      DUK_HEAPHDR_USER_FLAG(16)  /* 'String' object, array index exotic behavior */
6084 #define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS      DUK_HEAPHDR_USER_FLAG(17)  /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
6085 #define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ       DUK_HEAPHDR_USER_FLAG(18)  /* 'Proxy' object */
6086 #define DUK_HOBJECT_FLAG_SPECIAL_CALL          DUK_HEAPHDR_USER_FLAG(19)  /* special casing in call behavior, for .call(), .apply(), etc. */
6087
6088 #define DUK_HOBJECT_FLAG_CLASS_BASE            DUK_HEAPHDR_USER_FLAG_NUMBER(20)
6089 #define DUK_HOBJECT_FLAG_CLASS_BITS            5
6090
6091 #define DUK_HOBJECT_GET_CLASS_NUMBER(h)        \
6092         DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)
6093 #define DUK_HOBJECT_SET_CLASS_NUMBER(h,v)      \
6094         DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v))
6095
6096 #define DUK_HOBJECT_GET_CLASS_MASK(h)          \
6097         (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS))
6098
6099 /* Macro for creating flag initializer from a class number.
6100  * Unsigned type cast is needed to avoid warnings about coercing
6101  * a signed integer to an unsigned one; the largest class values
6102  * have the highest bit (bit 31) set which causes this.
6103  */
6104 #define DUK_HOBJECT_CLASS_AS_FLAGS(v)          (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
6105
6106 /* E5 Section 8.6.2 + custom classes */
6107 #define DUK_HOBJECT_CLASS_NONE                 0
6108 #define DUK_HOBJECT_CLASS_OBJECT               1
6109 #define DUK_HOBJECT_CLASS_ARRAY                2
6110 #define DUK_HOBJECT_CLASS_FUNCTION             3
6111 #define DUK_HOBJECT_CLASS_ARGUMENTS            4
6112 #define DUK_HOBJECT_CLASS_BOOLEAN              5
6113 #define DUK_HOBJECT_CLASS_DATE                 6
6114 #define DUK_HOBJECT_CLASS_ERROR                7
6115 #define DUK_HOBJECT_CLASS_JSON                 8
6116 #define DUK_HOBJECT_CLASS_MATH                 9
6117 #define DUK_HOBJECT_CLASS_NUMBER               10
6118 #define DUK_HOBJECT_CLASS_REGEXP               11
6119 #define DUK_HOBJECT_CLASS_STRING               12
6120 #define DUK_HOBJECT_CLASS_GLOBAL               13
6121 #define DUK_HOBJECT_CLASS_SYMBOL               14
6122 #define DUK_HOBJECT_CLASS_OBJENV               15  /* custom */
6123 #define DUK_HOBJECT_CLASS_DECENV               16  /* custom */
6124 #define DUK_HOBJECT_CLASS_POINTER              17  /* custom */
6125 #define DUK_HOBJECT_CLASS_THREAD               18  /* custom; implies DUK_HOBJECT_IS_THREAD */
6126 #define DUK_HOBJECT_CLASS_BUFOBJ_MIN           19
6127 #define DUK_HOBJECT_CLASS_ARRAYBUFFER          19  /* implies DUK_HOBJECT_IS_BUFOBJ */
6128 #define DUK_HOBJECT_CLASS_DATAVIEW             20
6129 #define DUK_HOBJECT_CLASS_INT8ARRAY            21
6130 #define DUK_HOBJECT_CLASS_UINT8ARRAY           22
6131 #define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY    23
6132 #define DUK_HOBJECT_CLASS_INT16ARRAY           24
6133 #define DUK_HOBJECT_CLASS_UINT16ARRAY          25
6134 #define DUK_HOBJECT_CLASS_INT32ARRAY           26
6135 #define DUK_HOBJECT_CLASS_UINT32ARRAY          27
6136 #define DUK_HOBJECT_CLASS_FLOAT32ARRAY         28
6137 #define DUK_HOBJECT_CLASS_FLOAT64ARRAY         29
6138 #define DUK_HOBJECT_CLASS_BUFOBJ_MAX           29
6139 #define DUK_HOBJECT_CLASS_MAX                  29
6140
6141 /* Class masks. */
6142 #define DUK_HOBJECT_CMASK_ALL                  ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
6143 #define DUK_HOBJECT_CMASK_NONE                 (1UL << DUK_HOBJECT_CLASS_NONE)
6144 #define DUK_HOBJECT_CMASK_ARGUMENTS            (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
6145 #define DUK_HOBJECT_CMASK_ARRAY                (1UL << DUK_HOBJECT_CLASS_ARRAY)
6146 #define DUK_HOBJECT_CMASK_BOOLEAN              (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
6147 #define DUK_HOBJECT_CMASK_DATE                 (1UL << DUK_HOBJECT_CLASS_DATE)
6148 #define DUK_HOBJECT_CMASK_ERROR                (1UL << DUK_HOBJECT_CLASS_ERROR)
6149 #define DUK_HOBJECT_CMASK_FUNCTION             (1UL << DUK_HOBJECT_CLASS_FUNCTION)
6150 #define DUK_HOBJECT_CMASK_JSON                 (1UL << DUK_HOBJECT_CLASS_JSON)
6151 #define DUK_HOBJECT_CMASK_MATH                 (1UL << DUK_HOBJECT_CLASS_MATH)
6152 #define DUK_HOBJECT_CMASK_NUMBER               (1UL << DUK_HOBJECT_CLASS_NUMBER)
6153 #define DUK_HOBJECT_CMASK_OBJECT               (1UL << DUK_HOBJECT_CLASS_OBJECT)
6154 #define DUK_HOBJECT_CMASK_REGEXP               (1UL << DUK_HOBJECT_CLASS_REGEXP)
6155 #define DUK_HOBJECT_CMASK_STRING               (1UL << DUK_HOBJECT_CLASS_STRING)
6156 #define DUK_HOBJECT_CMASK_GLOBAL               (1UL << DUK_HOBJECT_CLASS_GLOBAL)
6157 #define DUK_HOBJECT_CMASK_SYMBOL               (1UL << DUK_HOBJECT_CLASS_SYMBOL)
6158 #define DUK_HOBJECT_CMASK_OBJENV               (1UL << DUK_HOBJECT_CLASS_OBJENV)
6159 #define DUK_HOBJECT_CMASK_DECENV               (1UL << DUK_HOBJECT_CLASS_DECENV)
6160 #define DUK_HOBJECT_CMASK_POINTER              (1UL << DUK_HOBJECT_CLASS_POINTER)
6161 #define DUK_HOBJECT_CMASK_ARRAYBUFFER          (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
6162 #define DUK_HOBJECT_CMASK_DATAVIEW             (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
6163 #define DUK_HOBJECT_CMASK_INT8ARRAY            (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
6164 #define DUK_HOBJECT_CMASK_UINT8ARRAY           (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY)
6165 #define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY    (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY)
6166 #define DUK_HOBJECT_CMASK_INT16ARRAY           (1UL << DUK_HOBJECT_CLASS_INT16ARRAY)
6167 #define DUK_HOBJECT_CMASK_UINT16ARRAY          (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY)
6168 #define DUK_HOBJECT_CMASK_INT32ARRAY           (1UL << DUK_HOBJECT_CLASS_INT32ARRAY)
6169 #define DUK_HOBJECT_CMASK_UINT32ARRAY          (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY)
6170 #define DUK_HOBJECT_CMASK_FLOAT32ARRAY         (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
6171 #define DUK_HOBJECT_CMASK_FLOAT64ARRAY         (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
6172
6173 #define DUK_HOBJECT_CMASK_ALL_BUFOBJS \
6174         (DUK_HOBJECT_CMASK_ARRAYBUFFER | \
6175          DUK_HOBJECT_CMASK_DATAVIEW | \
6176          DUK_HOBJECT_CMASK_INT8ARRAY | \
6177          DUK_HOBJECT_CMASK_UINT8ARRAY | \
6178          DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \
6179          DUK_HOBJECT_CMASK_INT16ARRAY | \
6180          DUK_HOBJECT_CMASK_UINT16ARRAY | \
6181          DUK_HOBJECT_CMASK_INT32ARRAY | \
6182          DUK_HOBJECT_CMASK_UINT32ARRAY | \
6183          DUK_HOBJECT_CMASK_FLOAT32ARRAY | \
6184          DUK_HOBJECT_CMASK_FLOAT64ARRAY)
6185
6186 #define DUK_HOBJECT_IS_OBJENV(h)               (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
6187 #define DUK_HOBJECT_IS_DECENV(h)               (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
6188 #define DUK_HOBJECT_IS_ENV(h)                  (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
6189 #define DUK_HOBJECT_IS_ARRAY(h)                DUK_HOBJECT_HAS_EXOTIC_ARRAY((h))  /* Rely on class Array <=> exotic Array */
6190 #define DUK_HOBJECT_IS_BOUNDFUNC(h)            DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
6191 #define DUK_HOBJECT_IS_COMPFUNC(h)             DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
6192 #define DUK_HOBJECT_IS_NATFUNC(h)              DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
6193 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6194 #define DUK_HOBJECT_IS_BUFOBJ(h)               DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
6195 #else
6196 #define DUK_HOBJECT_IS_BUFOBJ(h)               0
6197 #endif
6198 #define DUK_HOBJECT_IS_THREAD(h)               (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_THREAD)
6199 #if defined(DUK_USE_ES6_PROXY)
6200 #define DUK_HOBJECT_IS_PROXY(h)                DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((h))
6201 #else
6202 #define DUK_HOBJECT_IS_PROXY(h)                0
6203 #endif
6204
6205 #define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h)    DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
6206                                                         DUK_HOBJECT_FLAG_COMPFUNC | \
6207                                                         DUK_HOBJECT_FLAG_NATFUNC)
6208
6209 #define DUK_HOBJECT_IS_FUNCTION(h)             DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
6210                                                         DUK_HOBJECT_FLAG_BOUNDFUNC | \
6211                                                         DUK_HOBJECT_FLAG_COMPFUNC | \
6212                                                         DUK_HOBJECT_FLAG_NATFUNC)
6213
6214 #define DUK_HOBJECT_IS_CALLABLE(h)             DUK_HOBJECT_HAS_CALLABLE((h))
6215
6216 /* Object has any exotic behavior(s). */
6217 #define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS      (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
6218                                                 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
6219                                                 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
6220                                                 DUK_HOBJECT_FLAG_BUFOBJ | \
6221                                                 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
6222 #define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h)     DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
6223
6224 /* Object has any virtual properties (not counting Proxy behavior). */
6225 #define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS     (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
6226                                                 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
6227                                                 DUK_HOBJECT_FLAG_BUFOBJ)
6228 #define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h)  DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS)
6229
6230 #define DUK_HOBJECT_HAS_EXTENSIBLE(h)          DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
6231 #define DUK_HOBJECT_HAS_CONSTRUCTABLE(h)       DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
6232 #define DUK_HOBJECT_HAS_CALLABLE(h)            DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
6233 #define DUK_HOBJECT_HAS_BOUNDFUNC(h)           DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
6234 #define DUK_HOBJECT_HAS_COMPFUNC(h)            DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
6235 #define DUK_HOBJECT_HAS_NATFUNC(h)             DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
6236 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6237 #define DUK_HOBJECT_HAS_BUFOBJ(h)              DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
6238 #else
6239 #define DUK_HOBJECT_HAS_BUFOBJ(h)              0
6240 #endif
6241 #define DUK_HOBJECT_HAS_FASTREFS(h)            DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
6242 #define DUK_HOBJECT_HAS_ARRAY_PART(h)          DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
6243 #define DUK_HOBJECT_HAS_STRICT(h)              DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
6244 #define DUK_HOBJECT_HAS_NOTAIL(h)              DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
6245 #define DUK_HOBJECT_HAS_NEWENV(h)              DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
6246 #define DUK_HOBJECT_HAS_NAMEBINDING(h)         DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
6247 #define DUK_HOBJECT_HAS_CREATEARGS(h)          DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
6248 #define DUK_HOBJECT_HAS_HAVE_FINALIZER(h)      DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
6249 #define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)        DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
6250 #define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)    DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
6251 #define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)    DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
6252 #if defined(DUK_USE_ES6_PROXY)
6253 #define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)     DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
6254 #else
6255 #define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)     0
6256 #endif
6257 #define DUK_HOBJECT_HAS_SPECIAL_CALL(h)        DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
6258
6259 #define DUK_HOBJECT_SET_EXTENSIBLE(h)          DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
6260 #define DUK_HOBJECT_SET_CONSTRUCTABLE(h)       DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
6261 #define DUK_HOBJECT_SET_CALLABLE(h)            DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
6262 #define DUK_HOBJECT_SET_BOUNDFUNC(h)           DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
6263 #define DUK_HOBJECT_SET_COMPFUNC(h)            DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
6264 #define DUK_HOBJECT_SET_NATFUNC(h)             DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
6265 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6266 #define DUK_HOBJECT_SET_BUFOBJ(h)              DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
6267 #endif
6268 #define DUK_HOBJECT_SET_FASTREFS(h)            DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
6269 #define DUK_HOBJECT_SET_ARRAY_PART(h)          DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
6270 #define DUK_HOBJECT_SET_STRICT(h)              DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
6271 #define DUK_HOBJECT_SET_NOTAIL(h)              DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
6272 #define DUK_HOBJECT_SET_NEWENV(h)              DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
6273 #define DUK_HOBJECT_SET_NAMEBINDING(h)         DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
6274 #define DUK_HOBJECT_SET_CREATEARGS(h)          DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
6275 #define DUK_HOBJECT_SET_HAVE_FINALIZER(h)      DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
6276 #define DUK_HOBJECT_SET_EXOTIC_ARRAY(h)        DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
6277 #define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h)    DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
6278 #define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h)    DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
6279 #if defined(DUK_USE_ES6_PROXY)
6280 #define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h)     DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
6281 #endif
6282 #define DUK_HOBJECT_SET_SPECIAL_CALL(h)        DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
6283
6284 #define DUK_HOBJECT_CLEAR_EXTENSIBLE(h)        DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
6285 #define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h)     DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
6286 #define DUK_HOBJECT_CLEAR_CALLABLE(h)          DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CALLABLE)
6287 #define DUK_HOBJECT_CLEAR_BOUNDFUNC(h)         DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
6288 #define DUK_HOBJECT_CLEAR_COMPFUNC(h)          DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
6289 #define DUK_HOBJECT_CLEAR_NATFUNC(h)           DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
6290 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6291 #define DUK_HOBJECT_CLEAR_BUFOBJ(h)            DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
6292 #endif
6293 #define DUK_HOBJECT_CLEAR_FASTREFS(h)          DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_FASTREFS)
6294 #define DUK_HOBJECT_CLEAR_ARRAY_PART(h)        DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
6295 #define DUK_HOBJECT_CLEAR_STRICT(h)            DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
6296 #define DUK_HOBJECT_CLEAR_NOTAIL(h)            DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
6297 #define DUK_HOBJECT_CLEAR_NEWENV(h)            DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
6298 #define DUK_HOBJECT_CLEAR_NAMEBINDING(h)       DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
6299 #define DUK_HOBJECT_CLEAR_CREATEARGS(h)        DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
6300 #define DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h)    DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_HAVE_FINALIZER)
6301 #define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h)      DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
6302 #define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h)  DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
6303 #define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h)  DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
6304 #if defined(DUK_USE_ES6_PROXY)
6305 #define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h)   DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
6306 #endif
6307 #define DUK_HOBJECT_CLEAR_SPECIAL_CALL(h)      DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_SPECIAL_CALL)
6308
6309 /* Object can/cannot use FASTREFS, i.e. has no strong reference fields beyond
6310  * duk_hobject base header.  This is used just for asserts so doesn't need to
6311  * be optimized.
6312  */
6313 #define DUK_HOBJECT_PROHIBITS_FASTREFS(h) \
6314         (DUK_HOBJECT_IS_COMPFUNC((h)) || DUK_HOBJECT_IS_DECENV((h)) || DUK_HOBJECT_IS_OBJENV((h)) || \
6315          DUK_HOBJECT_IS_BUFOBJ((h)) || DUK_HOBJECT_IS_THREAD((h)) || DUK_HOBJECT_IS_PROXY((h)) || \
6316          DUK_HOBJECT_IS_BOUNDFUNC((h)))
6317 #define DUK_HOBJECT_ALLOWS_FASTREFS(h) (!DUK_HOBJECT_PROHIBITS_FASTREFS((h)))
6318
6319 /* Flags used for property attributes in duk_propdesc and packed flags.
6320  * Must fit into 8 bits.
6321  */
6322 #define DUK_PROPDESC_FLAG_WRITABLE              (1U << 0)    /* E5 Section 8.6.1 */
6323 #define DUK_PROPDESC_FLAG_ENUMERABLE            (1U << 1)    /* E5 Section 8.6.1 */
6324 #define DUK_PROPDESC_FLAG_CONFIGURABLE          (1U << 2)    /* E5 Section 8.6.1 */
6325 #define DUK_PROPDESC_FLAG_ACCESSOR              (1U << 3)    /* accessor */
6326 #define DUK_PROPDESC_FLAG_VIRTUAL               (1U << 4)    /* property is virtual: used in duk_propdesc, never stored
6327                                                              * (used by e.g. buffer virtual properties)
6328                                                              */
6329 #define DUK_PROPDESC_FLAGS_MASK                 (DUK_PROPDESC_FLAG_WRITABLE | \
6330                                                  DUK_PROPDESC_FLAG_ENUMERABLE | \
6331                                                  DUK_PROPDESC_FLAG_CONFIGURABLE | \
6332                                                  DUK_PROPDESC_FLAG_ACCESSOR)
6333
6334 /* Additional flags which are passed in the same flags argument as property
6335  * flags but are not stored in object properties.
6336  */
6337 #define DUK_PROPDESC_FLAG_NO_OVERWRITE          (1U << 4)    /* internal define property: skip write silently if exists */
6338
6339 /* Convenience defines for property attributes. */
6340 #define DUK_PROPDESC_FLAGS_NONE                 0
6341 #define DUK_PROPDESC_FLAGS_W                    (DUK_PROPDESC_FLAG_WRITABLE)
6342 #define DUK_PROPDESC_FLAGS_E                    (DUK_PROPDESC_FLAG_ENUMERABLE)
6343 #define DUK_PROPDESC_FLAGS_C                    (DUK_PROPDESC_FLAG_CONFIGURABLE)
6344 #define DUK_PROPDESC_FLAGS_WE                   (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE)
6345 #define DUK_PROPDESC_FLAGS_WC                   (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
6346 #define DUK_PROPDESC_FLAGS_EC                   (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
6347 #define DUK_PROPDESC_FLAGS_WEC                  (DUK_PROPDESC_FLAG_WRITABLE | \
6348                                                  DUK_PROPDESC_FLAG_ENUMERABLE | \
6349                                                  DUK_PROPDESC_FLAG_CONFIGURABLE)
6350
6351 /* Flags for duk_hobject_get_own_propdesc() and variants. */
6352 #define DUK_GETDESC_FLAG_PUSH_VALUE          (1U << 0)  /* push value to stack */
6353 #define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP    (1U << 1)  /* don't throw for prototype loop */
6354
6355 /*
6356  *  Macro for object validity check
6357  *
6358  *  Assert for currently guaranteed relations between flags, for instance.
6359  */
6360
6361 #define DUK_ASSERT_HOBJECT_VALID(h) do { \
6362                 DUK_ASSERT((h) != NULL); \
6363                 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \
6364                            DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \
6365                 DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ((h)) || \
6366                            (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
6367                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \
6368                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \
6369                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \
6370                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || \
6371                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT16ARRAY || \
6372                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT16ARRAY || \
6373                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT32ARRAY || \
6374                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \
6375                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \
6376                             DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \
6377                 /* Object is an Array <=> object has exotic array behavior */ \
6378                 DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY((h))) || \
6379                            (DUK_HOBJECT_GET_CLASS_NUMBER((h)) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)))); \
6380         } while (0)
6381
6382 /*
6383  *  Macros to access the 'props' allocation.
6384  */
6385
6386 #if defined(DUK_USE_HEAPPTR16)
6387 #define DUK_HOBJECT_GET_PROPS(heap,h) \
6388         ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16))
6389 #define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
6390                 ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
6391         } while (0)
6392 #else
6393 #define DUK_HOBJECT_GET_PROPS(heap,h) \
6394         ((h)->props)
6395 #define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
6396                 (h)->props = (duk_uint8_t *) (x); \
6397         } while (0)
6398 #endif
6399
6400 #if defined(DUK_USE_HOBJECT_LAYOUT_1)
6401 /* LAYOUT 1 */
6402 #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
6403         ((duk_hstring **) (void *) ( \
6404                 DUK_HOBJECT_GET_PROPS((heap), (h)) \
6405         ))
6406 #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
6407         ((duk_propvalue *) (void *) ( \
6408                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6409                         DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \
6410         ))
6411 #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
6412         ((duk_uint8_t *) (void *) ( \
6413                 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
6414         ))
6415 #define DUK_HOBJECT_A_GET_BASE(heap,h) \
6416         ((duk_tval *) (void *) ( \
6417                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6418                         DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \
6419         ))
6420 #define DUK_HOBJECT_H_GET_BASE(heap,h) \
6421         ((duk_uint32_t *) (void *) ( \
6422                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6423                         DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6424                         DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
6425         ))
6426 #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
6427         ( \
6428                 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6429                 (n_arr) * sizeof(duk_tval) + \
6430                 (n_hash) * sizeof(duk_uint32_t) \
6431         )
6432 #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 { \
6433                 (set_e_k) = (duk_hstring **) (void *) (p_base); \
6434                 (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \
6435                 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \
6436                 (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \
6437                 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
6438         } while (0)
6439 #elif defined(DUK_USE_HOBJECT_LAYOUT_2)
6440 /* LAYOUT 2 */
6441 #if (DUK_USE_ALIGN_BY == 4)
6442 #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03)
6443 #elif (DUK_USE_ALIGN_BY == 8)
6444 #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07)
6445 #elif (DUK_USE_ALIGN_BY == 1)
6446 #define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0
6447 #else
6448 #error invalid DUK_USE_ALIGN_BY
6449 #endif
6450 #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
6451         ((duk_hstring **) (void *) ( \
6452                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6453                         DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
6454         ))
6455 #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
6456         ((duk_propvalue *) (void *) ( \
6457                 DUK_HOBJECT_GET_PROPS((heap), (h)) \
6458         ))
6459 #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
6460         ((duk_uint8_t *) (void *) ( \
6461                 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
6462         ))
6463 #define DUK_HOBJECT_A_GET_BASE(heap,h) \
6464         ((duk_tval *) (void *) ( \
6465                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6466                         DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6467                         DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \
6468         ))
6469 #define DUK_HOBJECT_H_GET_BASE(heap,h) \
6470         ((duk_uint32_t *) (void *) ( \
6471                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6472                         DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6473                         DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \
6474                         DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
6475         ))
6476 #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
6477         ( \
6478                 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
6479                 DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \
6480                 (n_arr) * sizeof(duk_tval) + \
6481                 (n_hash) * sizeof(duk_uint32_t) \
6482         )
6483 #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 { \
6484                 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
6485                 (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \
6486                 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \
6487                 (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \
6488                                                  sizeof(duk_uint8_t) * (n_ent) + \
6489                                                  DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \
6490                 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
6491         } while (0)
6492 #elif defined(DUK_USE_HOBJECT_LAYOUT_3)
6493 /* LAYOUT 3 */
6494 #define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
6495         ((duk_hstring **) (void *) ( \
6496                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6497                         DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \
6498                         DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
6499         ))
6500 #define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
6501         ((duk_propvalue *) (void *) ( \
6502                 DUK_HOBJECT_GET_PROPS((heap), (h)) \
6503         ))
6504 #define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
6505         ((duk_uint8_t *) (void *) ( \
6506                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6507                         DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
6508                         DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \
6509                         DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \
6510         ))
6511 #define DUK_HOBJECT_A_GET_BASE(heap,h) \
6512         ((duk_tval *) (void *) ( \
6513                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6514                         DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
6515         ))
6516 #define DUK_HOBJECT_H_GET_BASE(heap,h) \
6517         ((duk_uint32_t *) (void *) ( \
6518                 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
6519                         DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
6520                         DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
6521         ))
6522 #define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
6523         ( \
6524                 (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \
6525                 (n_arr) * sizeof(duk_tval) + \
6526                 (n_hash) * sizeof(duk_uint32_t) \
6527         )
6528 #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 { \
6529                 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
6530                 (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \
6531                 (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \
6532                 (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \
6533                 (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \
6534         } while (0)
6535 #else
6536 #error invalid hobject layout defines
6537 #endif  /* hobject property layout */
6538
6539 #define DUK_HOBJECT_P_ALLOC_SIZE(h) \
6540         DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h)))
6541
6542 #define DUK_HOBJECT_E_GET_KEY(heap,h,i)              (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
6543 #define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i)          (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
6544 #define DUK_HOBJECT_E_GET_VALUE(heap,h,i)            (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
6545 #define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i)        (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
6546 #define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i)       (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
6547 #define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i)   (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
6548 #define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i)     (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
6549 #define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
6550 #define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i)     (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
6551 #define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
6552 #define DUK_HOBJECT_E_GET_FLAGS(heap,h,i)            (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
6553 #define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i)        (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
6554 #define DUK_HOBJECT_A_GET_VALUE(heap,h,i)            (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
6555 #define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i)        (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
6556 #define DUK_HOBJECT_H_GET_INDEX(heap,h,i)            (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
6557 #define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i)        (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
6558
6559 #define DUK_HOBJECT_E_SET_KEY(heap,h,i,k)  do { \
6560                 DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \
6561         } while (0)
6562 #define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v)  do { \
6563                 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \
6564         } while (0)
6565 #define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v)  do { \
6566                 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \
6567         } while (0)
6568 #define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v)  do { \
6569                 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \
6570         } while (0)
6571 #define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v)  do { \
6572                 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
6573         } while (0)
6574 #define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f)  do { \
6575                 DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
6576         } while (0)
6577 #define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v)  do { \
6578                 DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
6579         } while (0)
6580 #define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \
6581         DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v))  /* alias for above */
6582 #define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v)  do { \
6583                 DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \
6584         } while (0)
6585
6586 #define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask)  do { \
6587                 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \
6588         } while (0)
6589
6590 #define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask)  do { \
6591                 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \
6592         } while (0)
6593
6594 #define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i)     ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0)
6595 #define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i)   ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
6596 #define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
6597 #define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i)     ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
6598
6599 #define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i)        DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
6600 #define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i)      DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
6601 #define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i)    DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
6602 #define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i)        DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
6603
6604 #define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i)      DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
6605 #define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i)    DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
6606 #define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i)  DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
6607 #define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i)      DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
6608
6609 #define DUK_PROPDESC_IS_WRITABLE(p)             (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0)
6610 #define DUK_PROPDESC_IS_ENUMERABLE(p)           (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
6611 #define DUK_PROPDESC_IS_CONFIGURABLE(p)         (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
6612 #define DUK_PROPDESC_IS_ACCESSOR(p)             (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
6613
6614 #define DUK_HOBJECT_HASHIDX_UNUSED              0xffffffffUL
6615 #define DUK_HOBJECT_HASHIDX_DELETED             0xfffffffeUL
6616
6617 /*
6618  *  Macros for accessing size fields
6619  */
6620
6621 #if defined(DUK_USE_OBJSIZES16)
6622 #define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16)
6623 #define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0)
6624 #define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16)
6625 #define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0)
6626 #define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++)
6627 #define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16)
6628 #define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0)
6629 #if defined(DUK_USE_HOBJECT_HASH_PART)
6630 #define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16)
6631 #define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0)
6632 #else
6633 #define DUK_HOBJECT_GET_HSIZE(h) 0
6634 #define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
6635 #endif
6636 #else
6637 #define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size)
6638 #define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0)
6639 #define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next)
6640 #define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0)
6641 #define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++)
6642 #define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size)
6643 #define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0)
6644 #if defined(DUK_USE_HOBJECT_HASH_PART)
6645 #define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size)
6646 #define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0)
6647 #else
6648 #define DUK_HOBJECT_GET_HSIZE(h) 0
6649 #define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
6650 #endif
6651 #endif
6652
6653 /*
6654  *  Misc
6655  */
6656
6657 /* Maximum prototype traversal depth.  Sanity limit which handles e.g.
6658  * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4).
6659  */
6660 #define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY      10000L
6661
6662 /*
6663  *  ECMAScript [[Class]]
6664  */
6665
6666 /* range check not necessary because all 4-bit values are mapped */
6667 #define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n)  duk_class_number_to_stridx[(n)]
6668
6669 #define DUK_HOBJECT_GET_CLASS_STRING(heap,h)          \
6670         DUK_HEAP_GET_STRING( \
6671                 (heap), \
6672                 DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \
6673         )
6674
6675 /*
6676  *  Macros for property handling
6677  */
6678
6679 #if defined(DUK_USE_HEAPPTR16)
6680 #define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
6681         ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16))
6682 #define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
6683                 (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
6684         } while (0)
6685 #else
6686 #define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
6687         ((h)->prototype)
6688 #define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
6689                 (h)->prototype = (x); \
6690         } while (0)
6691 #endif
6692
6693 /* Set prototype, DECREF earlier value, INCREF new value (tolerating NULLs). */
6694 #define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p)       duk_hobject_set_prototype_updref((thr), (h), (p))
6695
6696 /* Set initial prototype, assume NULL previous prototype, INCREF new value,
6697  * tolerate NULL.
6698  */
6699 #define DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr,h,proto) do { \
6700                 duk_hthread *duk__thr = (thr); \
6701                 duk_hobject *duk__obj = (h); \
6702                 duk_hobject *duk__proto = (proto); \
6703                 DUK_UNREF(duk__thr); \
6704                 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(duk__thr->heap, duk__obj) == NULL); \
6705                 DUK_HOBJECT_SET_PROTOTYPE(duk__thr->heap, duk__obj, duk__proto); \
6706                 DUK_HOBJECT_INCREF_ALLOWNULL(duk__thr, duk__proto); \
6707         } while (0)
6708
6709 /*
6710  *  Finalizer check
6711  */
6712
6713 #if defined(DUK_USE_HEAPPTR16)
6714 #define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((heap), (h))
6715 #else
6716 #define DUK_HOBJECT_HAS_FINALIZER_FAST(heap,h) duk_hobject_has_finalizer_fast_raw((h))
6717 #endif
6718
6719 /*
6720  *  Resizing and hash behavior
6721  */
6722
6723 /* Sanity limit on max number of properties (allocated, not necessarily used).
6724  * This is somewhat arbitrary, but if we're close to 2**32 properties some
6725  * algorithms will fail (e.g. hash size selection, next prime selection).
6726  * Also, we use negative array/entry table indices to indicate 'not found',
6727  * so anything above 0x80000000 will cause trouble now.
6728  */
6729 #if defined(DUK_USE_OBJSIZES16)
6730 #define DUK_HOBJECT_MAX_PROPERTIES       0x0000ffffUL
6731 #else
6732 #define DUK_HOBJECT_MAX_PROPERTIES       0x3fffffffUL   /* 2**30-1 ~= 1G properties */
6733 #endif
6734
6735 /* internal align target for props allocation, must be 2*n for some n */
6736 #if (DUK_USE_ALIGN_BY == 4)
6737 #define DUK_HOBJECT_ALIGN_TARGET         4
6738 #elif (DUK_USE_ALIGN_BY == 8)
6739 #define DUK_HOBJECT_ALIGN_TARGET         8
6740 #elif (DUK_USE_ALIGN_BY == 1)
6741 #define DUK_HOBJECT_ALIGN_TARGET         1
6742 #else
6743 #error invalid DUK_USE_ALIGN_BY
6744 #endif
6745
6746 /*
6747  *  PC-to-line constants
6748  */
6749
6750 #define DUK_PC2LINE_SKIP    64
6751
6752 /* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */
6753 #define DUK_PC2LINE_MAX_DIFF_LENGTH    (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8)
6754
6755 /*
6756  *  Struct defs
6757  */
6758
6759 struct duk_propaccessor {
6760         duk_hobject *get;
6761         duk_hobject *set;
6762 };
6763
6764 union duk_propvalue {
6765         /* The get/set pointers could be 16-bit pointer compressed but it
6766          * would make no difference on 32-bit platforms because duk_tval is
6767          * 8 bytes or more anyway.
6768          */
6769         duk_tval v;
6770         duk_propaccessor a;
6771 };
6772
6773 struct duk_propdesc {
6774         /* read-only values 'lifted' for ease of use */
6775         duk_small_uint_t flags;
6776         duk_hobject *get;
6777         duk_hobject *set;
6778
6779         /* for updating (all are set to < 0 for virtual properties) */
6780         duk_int_t e_idx;  /* prop index in 'entry part', < 0 if not there */
6781         duk_int_t h_idx;  /* prop index in 'hash part', < 0 if not there */
6782         duk_int_t a_idx;  /* prop index in 'array part', < 0 if not there */
6783 };
6784
6785 struct duk_hobject {
6786         duk_heaphdr hdr;
6787
6788         /*
6789          *  'props' contains {key,value,flags} entries, optional array entries, and
6790          *  an optional hash lookup table for non-array entries in a single 'sliced'
6791          *  allocation.  There are several layout options, which differ slightly in
6792          *  generated code size/speed and alignment/padding; duk_features.h selects
6793          *  the layout used.
6794          *
6795          *  Layout 1 (DUK_USE_HOBJECT_LAYOUT_1):
6796          *
6797          *    e_size * sizeof(duk_hstring *)         bytes of   entry keys (e_next gc reachable)
6798          *    e_size * sizeof(duk_propvalue)         bytes of   entry values (e_next gc reachable)
6799          *    e_size * sizeof(duk_uint8_t)           bytes of   entry flags (e_next gc reachable)
6800          *    a_size * sizeof(duk_tval)              bytes of   (opt) array values (plain only) (all gc reachable)
6801          *    h_size * sizeof(duk_uint32_t)          bytes of   (opt) hash indexes to entries (e_size),
6802          *                                                      0xffffffffUL = unused, 0xfffffffeUL = deleted
6803          *
6804          *  Layout 2 (DUK_USE_HOBJECT_LAYOUT_2):
6805          *
6806          *    e_size * sizeof(duk_propvalue)         bytes of   entry values (e_next gc reachable)
6807          *    e_size * sizeof(duk_hstring *)         bytes of   entry keys (e_next gc reachable)
6808          *    e_size * sizeof(duk_uint8_t) + pad     bytes of   entry flags (e_next gc reachable)
6809          *    a_size * sizeof(duk_tval)              bytes of   (opt) array values (plain only) (all gc reachable)
6810          *    h_size * sizeof(duk_uint32_t)          bytes of   (opt) hash indexes to entries (e_size),
6811          *                                                      0xffffffffUL = unused, 0xfffffffeUL = deleted
6812          *
6813          *  Layout 3 (DUK_USE_HOBJECT_LAYOUT_3):
6814          *
6815          *    e_size * sizeof(duk_propvalue)         bytes of   entry values (e_next gc reachable)
6816          *    a_size * sizeof(duk_tval)              bytes of   (opt) array values (plain only) (all gc reachable)
6817          *    e_size * sizeof(duk_hstring *)         bytes of   entry keys (e_next gc reachable)
6818          *    h_size * sizeof(duk_uint32_t)          bytes of   (opt) hash indexes to entries (e_size),
6819          *                                                      0xffffffffUL = unused, 0xfffffffeUL = deleted
6820          *    e_size * sizeof(duk_uint8_t)           bytes of   entry flags (e_next gc reachable)
6821          *
6822          *  In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms
6823          *  requiring 4 or 8 byte alignment.  This ensures proper alignment
6824          *  for the entries, at the cost of memory footprint.  However, it's
6825          *  probably preferable to use another layout on such platforms instead.
6826          *
6827          *  In layout 2, the key and value parts are swapped to avoid padding
6828          *  the key array on platforms requiring alignment by 8.  The flags part
6829          *  is padded to get alignment for array entries.  The 'e_next' count does
6830          *  not need to be rounded as in layout 1.
6831          *
6832          *  In layout 3, entry values and array values are always aligned properly,
6833          *  and assuming pointers are at most 8 bytes, so are the entry keys.  Hash
6834          *  indices will be properly aligned (assuming pointers are at least 4 bytes).
6835          *  Finally, flags don't need additional alignment.  This layout provides
6836          *  compact allocations without padding (even on platforms with alignment
6837          *  requirements) at the cost of a bit slower lookups.
6838          *
6839          *  Objects with few keys don't have a hash index; keys are looked up linearly,
6840          *  which is cache efficient because the keys are consecutive.  Larger objects
6841          *  have a hash index part which contains integer indexes to the entries part.
6842          *
6843          *  A single allocation reduces memory allocation overhead but requires more
6844          *  work when any part needs to be resized.  A sliced allocation for entries
6845          *  makes linear key matching faster on most platforms (more locality) and
6846          *  skimps on flags size (which would be followed by 3 bytes of padding in
6847          *  most architectures if entries were placed in a struct).
6848          *
6849          *  'props' also contains internal properties distinguished with a non-BMP
6850          *  prefix.  Often used properties should be placed early in 'props' whenever
6851          *  possible to make accessing them as fast a possible.
6852          */
6853
6854 #if defined(DUK_USE_HEAPPTR16)
6855         /* Located in duk_heaphdr h_extra16.  Subclasses of duk_hobject (like
6856          * duk_hcompfunc) are not free to use h_extra16 for this reason.
6857          */
6858 #else
6859         duk_uint8_t *props;
6860 #endif
6861
6862         /* prototype: the only internal property lifted outside 'e' as it is so central */
6863 #if defined(DUK_USE_HEAPPTR16)
6864         duk_uint16_t prototype16;
6865 #else
6866         duk_hobject *prototype;
6867 #endif
6868
6869 #if defined(DUK_USE_OBJSIZES16)
6870         duk_uint16_t e_size16;
6871         duk_uint16_t e_next16;
6872         duk_uint16_t a_size16;
6873 #if defined(DUK_USE_HOBJECT_HASH_PART)
6874         duk_uint16_t h_size16;
6875 #endif
6876 #else
6877         duk_uint32_t e_size;  /* entry part size */
6878         duk_uint32_t e_next;  /* index for next new key ([0,e_next[ are gc reachable) */
6879         duk_uint32_t a_size;  /* array part size (entirely gc reachable) */
6880 #if defined(DUK_USE_HOBJECT_HASH_PART)
6881         duk_uint32_t h_size;  /* hash part size or 0 if unused */
6882 #endif
6883 #endif
6884 };
6885
6886 /*
6887  *  Exposed data
6888  */
6889
6890 #if !defined(DUK_SINGLE_FILE)
6891 DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
6892 #endif  /* !DUK_SINGLE_FILE */
6893
6894 /*
6895  *  Prototypes
6896  */
6897
6898 /* alloc and init */
6899 DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
6900 DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6901 DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6902 DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6903 DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6904 DUK_INTERNAL_DECL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags);
6905 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6906 DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6907 #endif
6908 DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags);
6909 DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6910 DUK_INTERNAL_DECL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6911 DUK_INTERNAL_DECL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6912 DUK_INTERNAL_DECL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags);
6913
6914 /* resize */
6915 DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr,
6916                                                  duk_hobject *obj,
6917                                                  duk_uint32_t new_e_size,
6918                                                  duk_uint32_t new_a_size,
6919                                                  duk_uint32_t new_h_size,
6920                                                  duk_bool_t abandon_array);
6921 DUK_INTERNAL_DECL void duk_hobject_resize_entrypart(duk_hthread *thr,
6922                                                     duk_hobject *obj,
6923                                                     duk_uint32_t new_e_size);
6924 #if 0  /*unused*/
6925 DUK_INTERNAL_DECL void duk_hobject_resize_arraypart(duk_hthread *thr,
6926                                                     duk_hobject *obj,
6927                                                     duk_uint32_t new_a_size);
6928 #endif
6929
6930 /* low-level property functions */
6931 DUK_INTERNAL_DECL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
6932 DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
6933 DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs);
6934 DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
6935 DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags);
6936
6937 /* XXX: when optimizing for guaranteed property slots, use a guaranteed
6938  * slot for internal value; this call can then access it directly.
6939  */
6940 #define duk_hobject_get_internal_value_tval_ptr(heap,obj) \
6941         duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap)))
6942
6943 /* core property functions */
6944 DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
6945 DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag);
6946 DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag);
6947 DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
6948
6949 /* internal property functions */
6950 #define DUK_DELPROP_FLAG_THROW  (1U << 0)
6951 #define DUK_DELPROP_FLAG_FORCE  (1U << 1)
6952 DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
6953 DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
6954 DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
6955 DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags);
6956 DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj);
6957 #if defined(DUK_USE_HEAPPTR16)
6958 DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj);
6959 #else
6960 DUK_INTERNAL_DECL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj);
6961 #endif
6962
6963 /* helpers for defineProperty() and defineProperties() */
6964 DUK_INTERNAL_DECL void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
6965                                                                duk_idx_t idx_in,
6966                                                                duk_uint_t *out_defprop_flags,
6967                                                                duk_idx_t *out_idx_value,
6968                                                                duk_hobject **out_getter,
6969                                                                duk_hobject **out_setter);
6970 DUK_INTERNAL_DECL duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
6971                                                                 duk_uint_t defprop_flags,
6972                                                                 duk_hobject *obj,
6973                                                                 duk_hstring *key,
6974                                                                 duk_idx_t idx_value,
6975                                                                 duk_hobject *get,
6976                                                                 duk_hobject *set,
6977                                                                 duk_bool_t throw_flag);
6978
6979 /* Object built-in methods */
6980 DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx);
6981 DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
6982 DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
6983 DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags);
6984
6985 /* internal properties */
6986 DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
6987 DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
6988
6989 /* hobject management functions */
6990 DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
6991
6992 /* ES2015 proxy */
6993 #if defined(DUK_USE_ES6_PROXY)
6994 DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
6995 DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj);
6996 #endif
6997
6998 /* enumeration */
6999 DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags);
7000 DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags);
7001 DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value);
7002
7003 /* macros */
7004 DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
7005
7006 /* pc2line */
7007 #if defined(DUK_USE_PC2LINE)
7008 DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
7009 DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc);
7010 #endif
7011
7012 /* misc */
7013 DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop);
7014
7015 #if !defined(DUK_USE_OBJECT_BUILTIN)
7016 /* These declarations are needed when related built-in is disabled and
7017  * genbuiltins.py won't automatically emit the declerations.
7018  */
7019 DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr);
7020 DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_hthread *thr);
7021 #endif
7022
7023 #endif  /* DUK_HOBJECT_H_INCLUDED */
7024 /* #include duk_hcompfunc.h */
7025 #line 1 "duk_hcompfunc.h"
7026 /*
7027  *  Heap compiled function (ECMAScript function) representation.
7028  *
7029  *  There is a single data buffer containing the ECMAScript function's
7030  *  bytecode, constants, and inner functions.
7031  */
7032
7033 #if !defined(DUK_HCOMPFUNC_H_INCLUDED)
7034 #define DUK_HCOMPFUNC_H_INCLUDED
7035
7036 /*
7037  *  Field accessor macros
7038  */
7039
7040 /* XXX: casts could be improved, especially for GET/SET DATA */
7041
7042 #if defined(DUK_USE_HEAPPTR16)
7043 #define DUK_HCOMPFUNC_GET_DATA(heap,h) \
7044         ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
7045 #define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
7046                 (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7047         } while (0)
7048 #define DUK_HCOMPFUNC_GET_FUNCS(heap,h)  \
7049         ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
7050 #define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v)  do { \
7051                 (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7052         } while (0)
7053 #define DUK_HCOMPFUNC_GET_BYTECODE(heap,h)  \
7054         ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
7055 #define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v)  do { \
7056                 (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7057         } while (0)
7058 #define DUK_HCOMPFUNC_GET_LEXENV(heap,h)  \
7059         ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16)))
7060 #define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v)  do { \
7061                 (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7062         } while (0)
7063 #define DUK_HCOMPFUNC_GET_VARENV(heap,h)  \
7064         ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16)))
7065 #define DUK_HCOMPFUNC_SET_VARENV(heap,h,v)  do { \
7066                 (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7067         } while (0)
7068 #else
7069 #define DUK_HCOMPFUNC_GET_DATA(heap,h)  ((duk_hbuffer_fixed *) (void *) (h)->data)
7070 #define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
7071                 (h)->data = (duk_hbuffer *) (v); \
7072         } while (0)
7073 #define DUK_HCOMPFUNC_GET_FUNCS(heap,h)  ((h)->funcs)
7074 #define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v)  do { \
7075                 (h)->funcs = (v); \
7076         } while (0)
7077 #define DUK_HCOMPFUNC_GET_BYTECODE(heap,h)  ((h)->bytecode)
7078 #define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v)  do { \
7079                 (h)->bytecode = (v); \
7080         } while (0)
7081 #define DUK_HCOMPFUNC_GET_LEXENV(heap,h)  ((h)->lex_env)
7082 #define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v)  do { \
7083                 (h)->lex_env = (v); \
7084         } while (0)
7085 #define DUK_HCOMPFUNC_GET_VARENV(heap,h)  ((h)->var_env)
7086 #define DUK_HCOMPFUNC_SET_VARENV(heap,h,v)  do { \
7087                 (h)->var_env = (v); \
7088         } while (0)
7089 #endif
7090
7091 /*
7092  *  Accessor macros for function specific data areas
7093  */
7094
7095 /* Note: assumes 'data' is always a fixed buffer */
7096 #define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h)  \
7097         DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h)))
7098
7099 #define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h)  \
7100         ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h)))
7101
7102 #define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h)  \
7103         DUK_HCOMPFUNC_GET_FUNCS((heap), (h))
7104
7105 #define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h)  \
7106         DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))
7107
7108 #define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h)  \
7109         ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h)))
7110
7111 #define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h)  \
7112         ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)))
7113
7114 /* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */
7115 #define DUK_HCOMPFUNC_GET_CODE_END(heap,h)  \
7116         ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \
7117                         DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h))))
7118
7119 #define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h)  \
7120         ( \
7121          (duk_size_t) \
7122          ( \
7123            ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \
7124            ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \
7125          ) \
7126         )
7127
7128 #define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h)  \
7129         ( \
7130          (duk_size_t) \
7131          ( \
7132            ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \
7133            ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \
7134          ) \
7135         )
7136
7137 #define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h)  \
7138         ( \
7139          (duk_size_t) \
7140          ( \
7141            ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \
7142            ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \
7143          ) \
7144         )
7145
7146 #define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h)  \
7147         ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
7148
7149 #define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h)  \
7150         ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
7151
7152 #define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h)  \
7153         ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
7154
7155 /*
7156  *  Validity assert
7157  */
7158
7159 #define DUK_ASSERT_HCOMPFUNC_VALID(h) do { \
7160                 DUK_ASSERT((h) != NULL); \
7161         } while (0)
7162
7163 /*
7164  *  Main struct
7165  */
7166
7167 struct duk_hcompfunc {
7168         /* shared object part */
7169         duk_hobject obj;
7170
7171         /*
7172          *  Pointers to function data area for faster access.  Function
7173          *  data is a buffer shared between all closures of the same
7174          *  "template" function.  The data buffer is always fixed (non-
7175          *  dynamic, hence stable), with a layout as follows:
7176          *
7177          *    constants (duk_tval)
7178          *    inner functions (duk_hobject *)
7179          *    bytecode (duk_instr_t)
7180          *
7181          *  Note: bytecode end address can be computed from 'data' buffer
7182          *  size.  It is not strictly necessary functionally, assuming
7183          *  bytecode never jumps outside its allocated area.  However,
7184          *  it's a safety/robustness feature for avoiding the chance of
7185          *  executing random data as bytecode due to a compiler error.
7186          *
7187          *  Note: values in the data buffer must be incref'd (they will
7188          *  be decref'd on release) for every compiledfunction referring
7189          *  to the 'data' element.
7190          */
7191
7192         /* Data area, fixed allocation, stable data ptrs. */
7193 #if defined(DUK_USE_HEAPPTR16)
7194         duk_uint16_t data16;
7195 #else
7196         duk_hbuffer *data;
7197 #endif
7198
7199         /* No need for constants pointer (= same as data).
7200          *
7201          * When using 16-bit packing alignment to 4 is nice.  'funcs' will be
7202          * 4-byte aligned because 'constants' are duk_tvals.  For now the
7203          * inner function pointers are not compressed, so that 'bytecode' will
7204          * also be 4-byte aligned.
7205          */
7206 #if defined(DUK_USE_HEAPPTR16)
7207         duk_uint16_t funcs16;
7208         duk_uint16_t bytecode16;
7209 #else
7210         duk_hobject **funcs;
7211         duk_instr_t *bytecode;
7212 #endif
7213
7214         /* Lexenv: lexical environment of closure, NULL for templates.
7215          * Varenv: variable environment of closure, NULL for templates.
7216          */
7217 #if defined(DUK_USE_HEAPPTR16)
7218         duk_uint16_t lex_env16;
7219         duk_uint16_t var_env16;
7220 #else
7221         duk_hobject *lex_env;
7222         duk_hobject *var_env;
7223 #endif
7224
7225         /*
7226          *  'nregs' registers are allocated on function entry, at most 'nargs'
7227          *  are initialized to arguments, and the rest to undefined.  Arguments
7228          *  above 'nregs' are not mapped to registers.  All registers in the
7229          *  active stack range must be initialized because they are GC reachable.
7230          *  'nargs' is needed so that if the function is given more than 'nargs'
7231          *  arguments, the additional arguments do not 'clobber' registers
7232          *  beyond 'nregs' which must be consistently initialized to undefined.
7233          *
7234          *  Usually there is no need to know which registers are mapped to
7235          *  local variables.  Registers may be allocated to variable in any
7236          *  way (even including gaps).  However, a register-variable mapping
7237          *  must be the same for the duration of the function execution and
7238          *  the register cannot be used for anything else.
7239          *
7240          *  When looking up variables by name, the '_Varmap' map is used.
7241          *  When an activation closes, registers mapped to arguments are
7242          *  copied into the environment record based on the same map.  The
7243          *  reverse map (from register to variable) is not currently needed
7244          *  at run time, except for debugging, so it is not maintained.
7245          */
7246
7247         duk_uint16_t nregs;                /* regs to allocate */
7248         duk_uint16_t nargs;                /* number of arguments allocated to regs */
7249
7250         /*
7251          *  Additional control information is placed into the object itself
7252          *  as internal properties to avoid unnecessary fields for the
7253          *  majority of functions.  The compiler tries to omit internal
7254          *  control fields when possible.
7255          *
7256          *  Function templates:
7257          *
7258          *    {
7259          *      name: "func",    // declaration, named function expressions
7260          *      fileName: <debug info for creating nice errors>
7261          *      _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
7262          *      _Formals: [ "arg1", "arg2" ],
7263          *      _Source: "function func(arg1, arg2) { ... }",
7264          *      _Pc2line: <debug info for pc-to-line mapping>,
7265          *    }
7266          *
7267          *  Function instances:
7268          *
7269          *    {
7270          *      length: 2,
7271          *      prototype: { constructor: <func> },
7272          *      caller: <thrower>,
7273          *      arguments: <thrower>,
7274          *      name: "func",    // declaration, named function expressions
7275          *      fileName: <debug info for creating nice errors>
7276          *      _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
7277          *      _Formals: [ "arg1", "arg2" ],
7278          *      _Source: "function func(arg1, arg2) { ... }",
7279          *      _Pc2line: <debug info for pc-to-line mapping>,
7280          *    }
7281          *
7282          *  More detailed description of these properties can be found
7283          *  in the documentation.
7284          */
7285
7286 #if defined(DUK_USE_DEBUGGER_SUPPORT)
7287         /* Line number range for function.  Needed during debugging to
7288          * determine active breakpoints.
7289          */
7290         duk_uint32_t start_line;
7291         duk_uint32_t end_line;
7292 #endif
7293 };
7294
7295 #endif  /* DUK_HCOMPFUNC_H_INCLUDED */
7296 /* #include duk_hnatfunc.h */
7297 #line 1 "duk_hnatfunc.h"
7298 /*
7299  *  Heap native function representation.
7300  */
7301
7302 #if !defined(DUK_HNATFUNC_H_INCLUDED)
7303 #define DUK_HNATFUNC_H_INCLUDED
7304
7305 #define DUK_HNATFUNC_NARGS_VARARGS  ((duk_int16_t) -1)
7306 #define DUK_HNATFUNC_NARGS_MAX      ((duk_int16_t) 0x7fff)
7307
7308 struct duk_hnatfunc {
7309         /* shared object part */
7310         duk_hobject obj;
7311
7312         duk_c_function func;
7313         duk_int16_t nargs;
7314         duk_int16_t magic;
7315
7316         /* The 'magic' field allows an opaque 16-bit field to be accessed by the
7317          * Duktape/C function.  This allows, for instance, the same native function
7318          * to be used for a set of very similar functions, with the 'magic' field
7319          * providing the necessary non-argument flags / values to guide the behavior
7320          * of the native function.  The value is signed on purpose: it is easier to
7321          * convert a signed value to unsigned (simply AND with 0xffff) than vice
7322          * versa.
7323          *
7324          * Note: cannot place nargs/magic into the heaphdr flags, because
7325          * duk_hobject takes almost all flags already.
7326          */
7327 };
7328
7329 #endif  /* DUK_HNATFUNC_H_INCLUDED */
7330 /* #include duk_hboundfunc.h */
7331 #line 1 "duk_hboundfunc.h"
7332 /*
7333  *  Bound function representation.
7334  */
7335
7336 #if !defined(DUK_HBOUNDFUNC_H_INCLUDED)
7337 #define DUK_HBOUNDFUNC_H_INCLUDED
7338
7339 /* Artificial limit for args length.  Ensures arithmetic won't overflow
7340  * 32 bits when combining bound functions.
7341  */
7342 #define DUK_HBOUNDFUNC_MAX_ARGS 0x20000000UL
7343
7344 #define DUK_ASSERT_HBOUNDFUNC_VALID(h) do { \
7345                 DUK_ASSERT((h) != NULL); \
7346                 DUK_ASSERT(DUK_HOBJECT_IS_BOUNDFUNC((duk_hobject *) (h))); \
7347                 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&(h)->target) || \
7348                            (DUK_TVAL_IS_OBJECT(&(h)->target) && \
7349                             DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&(h)->target)))); \
7350                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&(h)->this_binding)); \
7351                 DUK_ASSERT((h)->nargs == 0 || (h)->args != NULL); \
7352         } while (0)
7353
7354 struct duk_hboundfunc {
7355         /* Shared object part. */
7356         duk_hobject obj;
7357
7358         /* Final target function, stored as duk_tval so that lightfunc can be
7359          * represented too.
7360          */
7361         duk_tval target;
7362
7363         /* This binding. */
7364         duk_tval this_binding;
7365
7366         /* Arguments to prepend. */
7367         duk_tval *args;  /* Separate allocation. */
7368         duk_idx_t nargs;
7369 };
7370
7371 #endif  /* DUK_HBOUNDFUNC_H_INCLUDED */
7372 /* #include duk_hbufobj.h */
7373 #line 1 "duk_hbufobj.h"
7374 /*
7375  *  Heap Buffer object representation.  Used for all Buffer variants.
7376  */
7377
7378 #if !defined(DUK_HBUFOBJ_H_INCLUDED)
7379 #define DUK_HBUFOBJ_H_INCLUDED
7380
7381 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
7382
7383 /* All element accessors are host endian now (driven by TypedArray spec). */
7384 #define DUK_HBUFOBJ_ELEM_UINT8           0
7385 #define DUK_HBUFOBJ_ELEM_UINT8CLAMPED    1
7386 #define DUK_HBUFOBJ_ELEM_INT8            2
7387 #define DUK_HBUFOBJ_ELEM_UINT16          3
7388 #define DUK_HBUFOBJ_ELEM_INT16           4
7389 #define DUK_HBUFOBJ_ELEM_UINT32          5
7390 #define DUK_HBUFOBJ_ELEM_INT32           6
7391 #define DUK_HBUFOBJ_ELEM_FLOAT32         7
7392 #define DUK_HBUFOBJ_ELEM_FLOAT64         8
7393 #define DUK_HBUFOBJ_ELEM_MAX             8
7394
7395 #define DUK_ASSERT_HBUFOBJ_VALID(h) do { \
7396                 DUK_ASSERT((h) != NULL); \
7397                 DUK_ASSERT((h)->shift <= 3); \
7398                 DUK_ASSERT((h)->elem_type <= DUK_HBUFOBJ_ELEM_MAX); \
7399                 DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8) || \
7400                            ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) || \
7401                            ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT8) || \
7402                            ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT16) || \
7403                            ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT16) || \
7404                            ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT32) || \
7405                            ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT32) || \
7406                            ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) || \
7407                            ((h)->shift == 3 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64)); \
7408                 DUK_ASSERT((h)->is_typedarray == 0 || (h)->is_typedarray == 1); \
7409                 DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) (h))); \
7410                 if ((h)->buf == NULL) { \
7411                         DUK_ASSERT((h)->offset == 0); \
7412                         DUK_ASSERT((h)->length == 0); \
7413                 } else { \
7414                         /* No assertions for offset or length; in particular, \
7415                          * it's OK for length to be longer than underlying \
7416                          * buffer.  Just ensure they don't wrap when added. \
7417                          */ \
7418                         DUK_ASSERT((h)->offset + (h)->length >= (h)->offset); \
7419                 } \
7420         } while (0)
7421
7422 /* Get the current data pointer (caller must ensure buf != NULL) as a
7423  * duk_uint8_t ptr.  Note that the result may be NULL if the underlying
7424  * buffer has zero size and is not a fixed buffer.
7425  */
7426 #define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \
7427         (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7428         (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
7429
7430 /* True if slice is full, i.e. offset is zero and length covers the entire
7431  * buffer.  This status may change independently of the duk_hbufobj if
7432  * the underlying buffer is dynamic and changes without the hbufobj
7433  * being changed.
7434  */
7435 #define DUK_HBUFOBJ_FULL_SLICE(h) \
7436         (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7437         ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
7438
7439 /* Validate that the whole slice [0,length[ is contained in the underlying
7440  * buffer.  Caller must ensure 'buf' != NULL.
7441  */
7442 #define DUK_HBUFOBJ_VALID_SLICE(h) \
7443         (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7444         ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
7445
7446 /* Validate byte read/write for virtual 'offset', i.e. check that the
7447  * offset, taking into account h->offset, is within the underlying
7448  * buffer size.  This is a safety check which is needed to ensure
7449  * that even a misconfigured duk_hbufobj never causes memory unsafe
7450  * behavior (e.g. if an underlying dynamic buffer changes after being
7451  * setup).  Caller must ensure 'buf' != NULL.
7452  */
7453 #define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \
7454         (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7455         ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
7456
7457 #define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \
7458         (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
7459         ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
7460
7461 /* Clamp an input byte length (already assumed to be within the nominal
7462  * duk_hbufobj 'length') to the current dynamic buffer limits to yield
7463  * a byte length limit that's safe for memory accesses.  This value can
7464  * be invalidated by any side effect because it may trigger a user
7465  * callback that resizes the underlying buffer.
7466  */
7467 #define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \
7468         (DUK_ASSERT_EXPR((h) != NULL), \
7469         duk_hbufobj_clamp_bytelength((h), (len)))
7470
7471 /* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */
7472 #define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h)  ((h)->is_typedarray)
7473
7474 struct duk_hbufobj {
7475         /* Shared object part. */
7476         duk_hobject obj;
7477
7478         /* Underlying buffer (refcounted), may be NULL. */
7479         duk_hbuffer *buf;
7480
7481         /* .buffer reference to an ArrayBuffer, may be NULL. */
7482         duk_hobject *buf_prop;
7483
7484         /* Slice and accessor information.
7485          *
7486          * Because the underlying buffer may be dynamic, these may be
7487          * invalidated by the buffer being modified so that both offset
7488          * and length should be validated before every access.  Behavior
7489          * when the underlying buffer has changed doesn't need to be clean:
7490          * virtual 'length' doesn't need to be affected, reads can return
7491          * zero/NaN, and writes can be ignored.
7492          *
7493          * Note that a data pointer cannot be precomputed because 'buf' may
7494          * be dynamic and its pointer unstable.
7495          */
7496
7497         duk_uint_t offset;       /* byte offset to buf */
7498         duk_uint_t length;       /* byte index limit for element access, exclusive */
7499         duk_uint8_t shift;       /* element size shift:
7500                                   *   0 = u8/i8
7501                                   *   1 = u16/i16
7502                                   *   2 = u32/i32/float
7503                                   *   3 = double
7504                                   */
7505         duk_uint8_t elem_type;   /* element type */
7506         duk_uint8_t is_typedarray;
7507 };
7508
7509 DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len);
7510 DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf);
7511 DUK_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);
7512 DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
7513 DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx);
7514
7515 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
7516 #endif  /* DUK_HBUFOBJ_H_INCLUDED */
7517 /* #include duk_hthread.h */
7518 #line 1 "duk_hthread.h"
7519 /*
7520  *  Heap thread object representation.
7521  *
7522  *  duk_hthread is also the 'context' for public API functions via a
7523  *  different typedef.  Most API calls operate on the topmost frame
7524  *  of the value stack only.
7525  */
7526
7527 #if !defined(DUK_HTHREAD_H_INCLUDED)
7528 #define DUK_HTHREAD_H_INCLUDED
7529
7530 /*
7531  *  Stack constants
7532  */
7533
7534 /* Initial valstack size, roughly 0.7kiB. */
7535 #define DUK_VALSTACK_INITIAL_SIZE       96U
7536
7537 /* Internal extra elements assumed on function entry, always added to
7538  * user-defined 'extra' for e.g. the duk_check_stack() call.
7539  */
7540 #define DUK_VALSTACK_INTERNAL_EXTRA     32U
7541
7542 /* Number of elements guaranteed to be user accessible (in addition to call
7543  * arguments) on Duktape/C function entry.  This is the major public API
7544  * commitment.
7545  */
7546 #define DUK_VALSTACK_API_ENTRY_MINIMUM  DUK_API_ENTRY_STACK
7547
7548 /*
7549  *  Activation defines
7550  */
7551
7552 #define DUK_ACT_FLAG_STRICT             (1U << 0)  /* function executes in strict mode */
7553 #define DUK_ACT_FLAG_TAILCALLED         (1U << 1)  /* activation has tail called one or more times */
7554 #define DUK_ACT_FLAG_CONSTRUCT          (1U << 2)  /* function executes as a constructor (called via "new") */
7555 #define DUK_ACT_FLAG_PREVENT_YIELD      (1U << 3)  /* activation prevents yield (native call or "new") */
7556 #define DUK_ACT_FLAG_DIRECT_EVAL        (1U << 4)  /* activation is a direct eval call */
7557 #define DUK_ACT_FLAG_CONSTRUCT_PROXY    (1U << 5)  /* activation is for Proxy 'construct' call, special return value handling */
7558 #define DUK_ACT_FLAG_BREAKPOINT_ACTIVE  (1U << 6)  /* activation has active breakpoint(s) */
7559
7560 #define DUK_ACT_GET_FUNC(act)           ((act)->func)
7561
7562 /*
7563  *  Flags for __FILE__ / __LINE__ registered into tracedata
7564  */
7565
7566 #define DUK_TB_FLAG_NOBLAME_FILELINE    (1U << 0)  /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
7567
7568 /*
7569  *  Catcher defines
7570  */
7571
7572 /* XXX: remove catcher type entirely */
7573
7574 /* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
7575 #define DUK_CAT_TYPE_MASK            0x0000000fUL
7576 #define DUK_CAT_TYPE_BITS            4
7577 #define DUK_CAT_LABEL_MASK           0xffffff00UL
7578 #define DUK_CAT_LABEL_BITS           24
7579 #define DUK_CAT_LABEL_SHIFT          8
7580
7581 #define DUK_CAT_FLAG_CATCH_ENABLED          (1U << 4)   /* catch part will catch */
7582 #define DUK_CAT_FLAG_FINALLY_ENABLED        (1U << 5)   /* finally part will catch */
7583 #define DUK_CAT_FLAG_CATCH_BINDING_ENABLED  (1U << 6)   /* request to create catch binding */
7584 #define DUK_CAT_FLAG_LEXENV_ACTIVE          (1U << 7)   /* catch or with binding is currently active */
7585
7586 #define DUK_CAT_TYPE_UNKNOWN         0
7587 #define DUK_CAT_TYPE_TCF             1
7588 #define DUK_CAT_TYPE_LABEL           2
7589
7590 #define DUK_CAT_GET_TYPE(c)          ((c)->flags & DUK_CAT_TYPE_MASK)
7591 #define DUK_CAT_GET_LABEL(c)         (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT)
7592
7593 #define DUK_CAT_HAS_CATCH_ENABLED(c)           ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED)
7594 #define DUK_CAT_HAS_FINALLY_ENABLED(c)         ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED)
7595 #define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c)   ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED)
7596 #define DUK_CAT_HAS_LEXENV_ACTIVE(c)           ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE)
7597
7598 #define DUK_CAT_SET_CATCH_ENABLED(c)    do { \
7599                 (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \
7600         } while (0)
7601 #define DUK_CAT_SET_FINALLY_ENABLED(c)  do { \
7602                 (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \
7603         } while (0)
7604 #define DUK_CAT_SET_CATCH_BINDING_ENABLED(c)    do { \
7605                 (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
7606         } while (0)
7607 #define DUK_CAT_SET_LEXENV_ACTIVE(c)    do { \
7608                 (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \
7609         } while (0)
7610
7611 #define DUK_CAT_CLEAR_CATCH_ENABLED(c)    do { \
7612                 (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \
7613         } while (0)
7614 #define DUK_CAT_CLEAR_FINALLY_ENABLED(c)  do { \
7615                 (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \
7616         } while (0)
7617 #define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c)    do { \
7618                 (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
7619         } while (0)
7620 #define DUK_CAT_CLEAR_LEXENV_ACTIVE(c)    do { \
7621                 (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \
7622         } while (0)
7623
7624 /*
7625  *  Thread defines
7626  */
7627
7628 #if defined(DUK_USE_ROM_STRINGS)
7629 #define DUK_HTHREAD_GET_STRING(thr,idx) \
7630         ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
7631 #else  /* DUK_USE_ROM_STRINGS */
7632 #if defined(DUK_USE_HEAPPTR16)
7633 #define DUK_HTHREAD_GET_STRING(thr,idx) \
7634         ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)]))
7635 #else
7636 #define DUK_HTHREAD_GET_STRING(thr,idx) \
7637         ((thr)->strs[(idx)])
7638 #endif
7639 #endif  /* DUK_USE_ROM_STRINGS */
7640
7641 /* values for the state field */
7642 #define DUK_HTHREAD_STATE_INACTIVE     1   /* thread not currently running */
7643 #define DUK_HTHREAD_STATE_RUNNING      2   /* thread currently running (only one at a time) */
7644 #define DUK_HTHREAD_STATE_RESUMED      3   /* thread resumed another thread (active but not running) */
7645 #define DUK_HTHREAD_STATE_YIELDED      4   /* thread has yielded */
7646 #define DUK_HTHREAD_STATE_TERMINATED   5   /* thread has terminated */
7647
7648 /* Executor interrupt default interval when nothing else requires a
7649  * smaller value.  The default interval must be small enough to allow
7650  * for reasonable execution timeout checking but large enough to keep
7651  * impact on execution performance low.
7652  */
7653 #if defined(DUK_USE_INTERRUPT_COUNTER)
7654 #define DUK_HTHREAD_INTCTR_DEFAULT     (256L * 1024L)
7655 #endif
7656
7657 /*
7658  *  Assert context is valid: non-NULL pointer, fields look sane.
7659  *
7660  *  This is used by public API call entrypoints to catch invalid 'ctx' pointers
7661  *  as early as possible; invalid 'ctx' pointers cause very odd and difficult to
7662  *  diagnose behavior so it's worth checking even when the check is not 100%.
7663  */
7664
7665 /* Assertions for internals. */
7666 #define DUK_ASSERT_HTHREAD_VALID(thr) do { \
7667                 DUK_ASSERT((thr) != NULL); \
7668                 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (thr)) == DUK_HTYPE_OBJECT); \
7669                 DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (thr))); \
7670                 DUK_ASSERT((thr)->unused1 == 0); \
7671                 DUK_ASSERT((thr)->unused2 == 0); \
7672         } while (0)
7673
7674 /* Assertions for public API calls; a bit stronger. */
7675 #define DUK_ASSERT_CTX_VALID(thr) do { \
7676                 DUK_ASSERT((thr) != NULL); \
7677                 DUK_ASSERT_HTHREAD_VALID((thr)); \
7678                 DUK_ASSERT((thr)->valstack != NULL); \
7679                 DUK_ASSERT((thr)->valstack_bottom != NULL); \
7680                 DUK_ASSERT((thr)->valstack_top != NULL); \
7681                 DUK_ASSERT((thr)->valstack_end != NULL); \
7682                 DUK_ASSERT((thr)->valstack_alloc_end != NULL); \
7683                 DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack); \
7684                 DUK_ASSERT((thr)->valstack_end >= (thr)->valstack); \
7685                 DUK_ASSERT((thr)->valstack_top >= (thr)->valstack); \
7686                 DUK_ASSERT((thr)->valstack_top >= (thr)->valstack_bottom); \
7687                 DUK_ASSERT((thr)->valstack_end >= (thr)->valstack_top); \
7688                 DUK_ASSERT((thr)->valstack_alloc_end >= (thr)->valstack_end); \
7689         } while (0)
7690
7691 /* Assertions for API call entry specifically.  Checks 'ctx' but also may
7692  * check internal state (e.g. not in a debugger transport callback).
7693  */
7694 #define DUK_ASSERT_API_ENTRY(thr) do { \
7695                 DUK_ASSERT_CTX_VALID((thr)); \
7696                 DUK_ASSERT((thr)->heap != NULL); \
7697                 DUK_ASSERT((thr)->heap->dbg_calling_transport == 0); \
7698         } while (0)
7699
7700 /*
7701  *  Assertion helpers.
7702  */
7703
7704 #define DUK_ASSERT_STRIDX_VALID(val) \
7705         DUK_ASSERT((duk_uint_t) (val) < DUK_HEAP_NUM_STRINGS)
7706
7707 #define DUK_ASSERT_BIDX_VALID(val) \
7708         DUK_ASSERT((duk_uint_t) (val) < DUK_NUM_BUILTINS)
7709
7710 /*
7711  *  Misc
7712  */
7713
7714 /* Fast access to 'this' binding.  Assumes there's a call in progress. */
7715 #define DUK_HTHREAD_THIS_PTR(thr) \
7716         (DUK_ASSERT_EXPR((thr) != NULL), \
7717          DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
7718          (thr)->valstack_bottom - 1)
7719
7720 /*
7721  *  Struct defines
7722  */
7723
7724 /* Fields are ordered for alignment/packing. */
7725 struct duk_activation {
7726         duk_tval tv_func;       /* borrowed: full duk_tval for function being executed; for lightfuncs */
7727         duk_hobject *func;      /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
7728         duk_activation *parent; /* previous (parent) activation (or NULL if none) */
7729         duk_hobject *var_env;   /* current variable environment (may be NULL if delayed) */
7730         duk_hobject *lex_env;   /* current lexical environment (may be NULL if delayed) */
7731         duk_catcher *cat;       /* current catcher (or NULL) */
7732
7733 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
7734         /* Previous value of 'func' caller, restored when unwound.  Only in use
7735          * when 'func' is non-strict.
7736          */
7737         duk_hobject *prev_caller;
7738 #endif
7739
7740         duk_instr_t *curr_pc;   /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
7741
7742         /* bottom_byteoff and retval_byteoff are only used for book-keeping
7743          * of ECMAScript-initiated calls, to allow returning to an ECMAScript
7744          * function properly.
7745          */
7746
7747         /* Bottom of valstack for this activation, used to reset
7748          * valstack_bottom on return; offset is absolute.  There's
7749          * no need to track 'top' because native call handling deals
7750          * with that using locals, and for ECMAScript returns 'nregs'
7751          * indicates the necessary top.
7752          */
7753         duk_size_t bottom_byteoff;
7754
7755         /* Return value when returning to this activation (points to caller
7756          * reg, not callee reg); offset is absolute (only set if activation is
7757          * not topmost).
7758          *
7759          * Note: bottom_byteoff is always set, while retval_byteoff is only
7760          * applicable for activations below the topmost one.  Currently
7761          * retval_byteoff for the topmost activation is considered garbage
7762          * (and it not initialized on entry or cleared on return; may contain
7763          * previous or garbage values).
7764          */
7765         duk_size_t retval_byteoff;
7766
7767         /* Current 'this' binding is the value just below bottom.
7768          * Previously, 'this' binding was handled with an index to the
7769          * (calling) valstack.  This works for everything except tail
7770          * calls, which must not "accumulate" valstack temps.
7771          */
7772
7773         /* Value stack reserve (valstack_end) byte offset to be restored
7774          * when returning to this activation.  Only used by the bytecode
7775          * executor.
7776          */
7777         duk_size_t reserve_byteoff;
7778
7779 #if defined(DUK_USE_DEBUGGER_SUPPORT)
7780         duk_uint32_t prev_line; /* needed for stepping */
7781 #endif
7782
7783         duk_small_uint_t flags;
7784 };
7785
7786 struct duk_catcher {
7787         duk_catcher *parent;            /* previous (parent) catcher (or NULL if none) */
7788         duk_hstring *h_varname;         /* borrowed reference to catch variable name (or NULL if none) */
7789                                         /* (reference is valid as long activation exists) */
7790         duk_instr_t *pc_base;           /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
7791         duk_size_t idx_base;            /* idx_base and idx_base+1 get completion value and type */
7792         duk_uint32_t flags;             /* type and control flags, label number */
7793         /* XXX: could pack 'flags' and 'idx_base' to same value in practice,
7794          * on 32-bit targets this would make duk_catcher 16 bytes.
7795          */
7796 };
7797
7798 struct duk_hthread {
7799         /* Shared object part */
7800         duk_hobject obj;
7801
7802         /* Pointer to bytecode executor's 'curr_pc' variable.  Used to copy
7803          * the current PC back into the topmost activation when activation
7804          * state is about to change (or "syncing" is otherwise needed).  This
7805          * is rather awkward but important for performance, see execution.rst.
7806          */
7807         duk_instr_t **ptr_curr_pc;
7808
7809         /* Backpointers. */
7810         duk_heap *heap;
7811
7812         /* Current strictness flag: affects API calls. */
7813         duk_uint8_t strict;
7814
7815         /* Thread state. */
7816         duk_uint8_t state;
7817         duk_uint8_t unused1;
7818         duk_uint8_t unused2;
7819
7820         /* XXX: Valstack and callstack are currently assumed to have non-NULL
7821          * pointers.  Relaxing this would not lead to big benefits (except
7822          * perhaps for terminated threads).
7823          */
7824
7825         /* Value stack: these are expressed as pointers for faster stack
7826          * manipulation.  [valstack,valstack_top[ is GC-reachable,
7827          * [valstack_top,valstack_alloc_end[ is not GC-reachable but kept
7828          * initialized as 'undefined'.  [valstack,valstack_end[ is the
7829          * guaranteed/reserved space and the valstack cannot be resized to
7830          * a smaller size.  [valstack_end,valstack_alloc_end[ is currently
7831          * allocated slack that can be used to grow the current guaranteed
7832          * space but may be shrunk away without notice.
7833          *
7834          *
7835          * <----------------------- guaranteed --->
7836          *                                        <---- slack --->
7837          *               <--- frame --->
7838          * .-------------+=============+----------+--------------.
7839          * |xxxxxxxxxxxxx|yyyyyyyyyyyyy|uuuuuuuuuu|uuuuuuuuuuuuuu|
7840          * `-------------+=============+----------+--------------'
7841          *
7842          * ^             ^             ^          ^              ^
7843          * |             |             |          |              |
7844          * valstack      bottom        top        end            alloc_end
7845          *
7846          *     xxx = arbitrary values, below current frame
7847          *     yyy = arbitrary values, inside current frame
7848          *     uuu = outside active value stack, initialized to 'undefined'
7849          */
7850         duk_tval *valstack;                     /* start of valstack allocation */
7851         duk_tval *valstack_end;                 /* end of valstack reservation/guarantee (exclusive) */
7852         duk_tval *valstack_alloc_end;           /* end of valstack allocation */
7853         duk_tval *valstack_bottom;              /* bottom of current frame */
7854         duk_tval *valstack_top;                 /* top of current frame (exclusive) */
7855
7856         /* Call stack, represented as a linked list starting from the current
7857          * activation (or NULL if nothing is active).
7858          */
7859         duk_activation *callstack_curr;         /* current activation (or NULL if none) */
7860         duk_size_t callstack_top;               /* number of activation records in callstack (0 if none) */
7861         duk_size_t callstack_preventcount;      /* number of activation records in callstack preventing a yield */
7862
7863         /* Yield/resume book-keeping. */
7864         duk_hthread *resumer;                   /* who resumed us (if any) */
7865
7866         /* Current compiler state (if any), used for augmenting SyntaxErrors. */
7867         duk_compiler_ctx *compile_ctx;
7868
7869 #if defined(DUK_USE_INTERRUPT_COUNTER)
7870         /* Interrupt counter for triggering a slow path check for execution
7871          * timeout, debugger interaction such as breakpoints, etc.  The value
7872          * is valid for the current running thread, and both the init and
7873          * counter values are copied whenever a thread switch occurs.  It's
7874          * important for the counter to be conveniently accessible for the
7875          * bytecode executor inner loop for performance reasons.
7876          */
7877         duk_int_t interrupt_counter;    /* countdown state */
7878         duk_int_t interrupt_init;       /* start value for current countdown */
7879 #endif
7880
7881         /* Builtin-objects; may or may not be shared with other threads,
7882          * threads existing in different "compartments" will have different
7883          * built-ins.  Must be stored on a per-thread basis because there
7884          * is no intermediate structure for a thread group / compartment.
7885          * This takes quite a lot of space, currently 43x4 = 172 bytes on
7886          * 32-bit platforms.
7887          *
7888          * In some cases the builtins array could be ROM based, but it's
7889          * sometimes edited (e.g. for sandboxing) so it's better to keep
7890          * this array in RAM.
7891          */
7892         duk_hobject *builtins[DUK_NUM_BUILTINS];
7893
7894         /* Convenience copies from heap/vm for faster access. */
7895 #if defined(DUK_USE_ROM_STRINGS)
7896         /* No field needed when strings are in ROM. */
7897 #else
7898 #if defined(DUK_USE_HEAPPTR16)
7899         duk_uint16_t *strs16;
7900 #else
7901         duk_hstring **strs;
7902 #endif
7903 #endif
7904 };
7905
7906 /*
7907  *  Prototypes
7908  */
7909
7910 DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to);
7911 DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
7912 DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
7913 DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
7914
7915 DUK_INTERNAL_DECL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr);
7916 DUK_INTERNAL_DECL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act);
7917 DUK_INTERNAL_DECL void duk_hthread_activation_unwind_norz(duk_hthread *thr);
7918 DUK_INTERNAL_DECL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr);
7919 DUK_INTERNAL_DECL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level);
7920
7921 DUK_INTERNAL_DECL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr);
7922 DUK_INTERNAL_DECL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat);
7923 DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act);
7924 DUK_INTERNAL_DECL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act);
7925
7926 #if defined(DUK_USE_FINALIZER_TORTURE)
7927 DUK_INTERNAL_DECL void duk_hthread_valstack_torture_realloc(duk_hthread *thr);
7928 #endif
7929
7930 DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud);  /* indirect allocs */
7931
7932 #if defined(DUK_USE_DEBUGGER_SUPPORT)
7933 DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
7934 #endif
7935 DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act);
7936 DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr);
7937 DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
7938
7939 #endif  /* DUK_HTHREAD_H_INCLUDED */
7940 /* #include duk_harray.h */
7941 #line 1 "duk_harray.h"
7942 /*
7943  *  Array object representation, used for actual Array instances.
7944  *
7945  *  All objects with the exotic array behavior (which must coincide with having
7946  *  internal class array) MUST be duk_harrays.  No other object can be a
7947  *  duk_harray.  However, duk_harrays may not always have an array part.
7948  */
7949
7950 #if !defined(DUK_HARRAY_H_INCLUDED)
7951 #define DUK_HARRAY_H_INCLUDED
7952
7953 #define DUK_ASSERT_HARRAY_VALID(h) do { \
7954                 DUK_ASSERT((h) != NULL); \
7955                 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) (h))); \
7956                 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) (h))); \
7957         } while (0)
7958
7959 #define DUK_HARRAY_LENGTH_WRITABLE(h)         (!(h)->length_nonwritable)
7960 #define DUK_HARRAY_LENGTH_NONWRITABLE(h)      ((h)->length_nonwritable)
7961 #define DUK_HARRAY_SET_LENGTH_WRITABLE(h)     do { (h)->length_nonwritable = 0; } while (0)
7962 #define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h)  do { (h)->length_nonwritable = 1; } while (0)
7963
7964 struct duk_harray {
7965         /* Shared object part. */
7966         duk_hobject obj;
7967
7968         /* Array .length.
7969          *
7970          * At present Array .length may be smaller, equal, or even larger
7971          * than the allocated underlying array part.  Fast path code must
7972          * always take this into account carefully.
7973          */
7974         duk_uint32_t length;
7975
7976         /* Array .length property attributes.  The property is always
7977          * non-enumerable and non-configurable.  It's initially writable
7978          * but per Object.defineProperty() rules it can be made non-writable
7979          * even if it is non-configurable.  Thus we need to track the
7980          * writability explicitly.
7981          *
7982          * XXX: this field to be eliminated and moved into duk_hobject
7983          * flags field to save space.
7984          */
7985         duk_bool_t length_nonwritable;
7986 };
7987
7988 #endif  /* DUK_HARRAY_H_INCLUDED */
7989 /* #include duk_henv.h */
7990 #line 1 "duk_henv.h"
7991 /*
7992  *  Environment object representation.
7993  */
7994
7995 #if !defined(DUK_HENV_H_INCLUDED)
7996 #define DUK_HENV_H_INCLUDED
7997
7998 #define DUK_ASSERT_HDECENV_VALID(h) do { \
7999                 DUK_ASSERT((h) != NULL); \
8000                 DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) (h))); \
8001                 DUK_ASSERT((h)->thread == NULL || (h)->varmap != NULL); \
8002         } while (0)
8003
8004 #define DUK_ASSERT_HOBJENV_VALID(h) do { \
8005                 DUK_ASSERT((h) != NULL); \
8006                 DUK_ASSERT(DUK_HOBJECT_IS_OBJENV((duk_hobject *) (h))); \
8007                 DUK_ASSERT((h)->target != NULL); \
8008                 DUK_ASSERT((h)->has_this == 0 || (h)->has_this == 1); \
8009         } while (0)
8010
8011 struct duk_hdecenv {
8012         /* Shared object part. */
8013         duk_hobject obj;
8014
8015         /* These control variables provide enough information to access live
8016          * variables for a closure that is still open.  If thread == NULL,
8017          * the record is closed and the identifiers are in the property table.
8018          */
8019         duk_hthread *thread;
8020         duk_hobject *varmap;
8021         duk_size_t regbase_byteoff;
8022 };
8023
8024 struct duk_hobjenv {
8025         /* Shared object part. */
8026         duk_hobject obj;
8027
8028         /* Target object and 'this' binding for object binding. */
8029         duk_hobject *target;
8030
8031         /* The 'target' object is used as a this binding in only some object
8032          * environments.  For example, the global environment does not provide
8033          * a this binding, but a with statement does.
8034          */
8035         duk_bool_t has_this;
8036 };
8037
8038 #endif  /* DUK_HENV_H_INCLUDED */
8039 /* #include duk_hbuffer.h */
8040 #line 1 "duk_hbuffer.h"
8041 /*
8042  *  Heap buffer representation.
8043  *
8044  *  Heap allocated user data buffer which is either:
8045  *
8046  *    1. A fixed size buffer (data follows header statically)
8047  *    2. A dynamic size buffer (data pointer follows header)
8048  *
8049  *  The data pointer for a variable size buffer of zero size may be NULL.
8050  */
8051
8052 #if !defined(DUK_HBUFFER_H_INCLUDED)
8053 #define DUK_HBUFFER_H_INCLUDED
8054
8055 /*
8056  *  Flags
8057  *
8058  *  Fixed buffer:     0
8059  *  Dynamic buffer:   DUK_HBUFFER_FLAG_DYNAMIC
8060  *  External buffer:  DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL
8061  */
8062
8063 #define DUK_HBUFFER_FLAG_DYNAMIC                  DUK_HEAPHDR_USER_FLAG(0)    /* buffer is behind a pointer, dynamic or external */
8064 #define DUK_HBUFFER_FLAG_EXTERNAL                 DUK_HEAPHDR_USER_FLAG(1)    /* buffer pointer is to an externally allocated buffer */
8065
8066 #define DUK_HBUFFER_HAS_DYNAMIC(x)                DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
8067 #define DUK_HBUFFER_HAS_EXTERNAL(x)               DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
8068
8069 #define DUK_HBUFFER_SET_DYNAMIC(x)                DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
8070 #define DUK_HBUFFER_SET_EXTERNAL(x)               DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
8071
8072 #define DUK_HBUFFER_CLEAR_DYNAMIC(x)              DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
8073 #define DUK_HBUFFER_CLEAR_EXTERNAL(x)             DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
8074
8075 /*
8076  *  Misc defines
8077  */
8078
8079 /* Impose a maximum buffer length for now.  Restricted artificially to
8080  * ensure resize computations or adding a heap header length won't
8081  * overflow size_t and that a signed duk_int_t can hold a buffer
8082  * length.  The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN.
8083  */
8084
8085 #if defined(DUK_USE_BUFLEN16)
8086 #define DUK_HBUFFER_MAX_BYTELEN                   (0x0000ffffUL)
8087 #else
8088 /* Intentionally not 0x7fffffffUL; at least JSON code expects that
8089  * 2*len + 2 fits in 32 bits.
8090  */
8091 #define DUK_HBUFFER_MAX_BYTELEN                   (0x7ffffffeUL)
8092 #endif
8093
8094 /*
8095  *  Field access
8096  */
8097
8098 #if defined(DUK_USE_BUFLEN16)
8099 /* size stored in duk_heaphdr unused flag bits */
8100 #define DUK_HBUFFER_GET_SIZE(x)     ((x)->hdr.h_flags >> 16)
8101 #define DUK_HBUFFER_SET_SIZE(x,v)   do { \
8102                 duk_size_t duk__v; \
8103                 duk__v = (v); \
8104                 DUK_ASSERT(duk__v <= 0xffffUL); \
8105                 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \
8106         } while (0)
8107 #define DUK_HBUFFER_ADD_SIZE(x,dv)  do { \
8108                 (x)->hdr.h_flags += ((dv) << 16); \
8109         } while (0)
8110 #define DUK_HBUFFER_SUB_SIZE(x,dv)  do { \
8111                 (x)->hdr.h_flags -= ((dv) << 16); \
8112         } while (0)
8113 #else
8114 #define DUK_HBUFFER_GET_SIZE(x)     (((duk_hbuffer *) (x))->size)
8115 #define DUK_HBUFFER_SET_SIZE(x,v)   do { \
8116                 ((duk_hbuffer *) (x))->size = (v); \
8117         } while (0)
8118 #define DUK_HBUFFER_ADD_SIZE(x,dv)  do { \
8119                 (x)->size += (dv); \
8120         } while (0)
8121 #define DUK_HBUFFER_SUB_SIZE(x,dv)  do { \
8122                 (x)->size -= (dv); \
8123         } while (0)
8124 #endif
8125
8126 #define DUK_HBUFFER_FIXED_GET_SIZE(x)       DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
8127 #define DUK_HBUFFER_FIXED_SET_SIZE(x,v)     DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x))
8128
8129 #define DUK_HBUFFER_DYNAMIC_GET_SIZE(x)     DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
8130 #define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v)   DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
8131 #define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv)  DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv))
8132 #define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv)  DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv))
8133
8134 #define DUK_HBUFFER_EXTERNAL_GET_SIZE(x)    DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
8135 #define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v)  DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
8136
8137 #define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x)    ((duk_uint8_t *) (((duk_hbuffer_fixed *) (void *) (x)) + 1))
8138
8139 #if defined(DUK_USE_HEAPPTR16)
8140 #define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \
8141         ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16))
8142 #define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v)     do { \
8143                 ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
8144         } while (0)
8145 #define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x)  do { \
8146                 ((duk_heaphdr *) (x))->h_extra16 = 0;  /* assume 0 <=> NULL */ \
8147         } while (0)
8148 #else
8149 #define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x)       ((x)->curr_alloc)
8150 #define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v)     do { \
8151                 (x)->curr_alloc = (void *) (v); \
8152         } while (0)
8153 #define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x)  do { \
8154                 (x)->curr_alloc = (void *) NULL; \
8155         } while (0)
8156 #endif
8157
8158 /* No pointer compression because pointer is potentially outside of
8159  * Duktape heap.
8160  */
8161 #if defined(DUK_USE_HEAPPTR16)
8162 #define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
8163         ((void *) (x)->curr_alloc)
8164 #define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v)     do { \
8165                 (x)->curr_alloc = (void *) (v); \
8166         } while (0)
8167 #define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x)  do { \
8168                 (x)->curr_alloc = (void *) NULL; \
8169         } while (0)
8170 #else
8171 #define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
8172         ((void *) (x)->curr_alloc)
8173 #define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v)     do { \
8174                 (x)->curr_alloc = (void *) (v); \
8175         } while (0)
8176 #define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x)  do { \
8177                 (x)->curr_alloc = (void *) NULL; \
8178         } while (0)
8179 #endif
8180
8181 /* Get a pointer to the current buffer contents (matching current allocation
8182  * size).  May be NULL for zero size dynamic/external buffer.
8183  */
8184 #if defined(DUK_USE_HEAPPTR16)
8185 #define DUK_HBUFFER_GET_DATA_PTR(heap,x)  ( \
8186         DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
8187                 ( \
8188                         DUK_HBUFFER_HAS_EXTERNAL((x)) ? \
8189                                 DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \
8190                                 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \
8191                 ) : \
8192                 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \
8193         )
8194 #else
8195 /* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external
8196  * have the same layout so checking for fixed vs. dynamic (or external) is enough.
8197  */
8198 #define DUK_HBUFFER_GET_DATA_PTR(heap,x)  ( \
8199         DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
8200                 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \
8201                 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (void *) (x)) \
8202         )
8203 #endif
8204
8205 /*
8206  *  Structs
8207  */
8208
8209 /* Shared prefix for all buffer types. */
8210 struct duk_hbuffer {
8211         duk_heaphdr hdr;
8212
8213         /* It's not strictly necessary to track the current size, but
8214          * it is useful for writing robust native code.
8215          */
8216
8217         /* Current size. */
8218 #if defined(DUK_USE_BUFLEN16)
8219         /* Stored in duk_heaphdr unused flags. */
8220 #else
8221         duk_size_t size;
8222 #endif
8223
8224         /*
8225          *  Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC
8226          *  flag.
8227          *
8228          *  If the flag is clear (the buffer is a fixed size one), the buffer
8229          *  data follows the header directly, consisting of 'size' bytes.
8230          *
8231          *  If the flag is set, the actual buffer is allocated separately, and
8232          *  a few control fields follow the header.  Specifically:
8233          *
8234          *    - a "void *" pointing to the current allocation
8235          *    - a duk_size_t indicating the full allocated size (always >= 'size')
8236          *
8237          *  If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated
8238          *  by user code, so that Duktape won't be able to resize it and won't
8239          *  free it.  This allows buffers to point to e.g. an externally
8240          *  allocated structure such as a frame buffer.
8241          *
8242          *  Unlike strings, no terminator byte (NUL) is guaranteed after the
8243          *  data.  This would be convenient, but would pad aligned user buffers
8244          *  unnecessarily upwards in size.  For instance, if user code requested
8245          *  a 64-byte dynamic buffer, 65 bytes would actually be allocated which
8246          *  would then potentially round upwards to perhaps 68 or 72 bytes.
8247          */
8248 };
8249
8250 /* Fixed buffer; data follows struct, with proper alignment guaranteed by
8251  * struct size.
8252  */
8253 #if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
8254 #pragma pack(push, 8)
8255 #endif
8256 struct duk_hbuffer_fixed {
8257         /* A union is used here as a portable struct size / alignment trick:
8258          * by adding a 32-bit or a 64-bit (unused) union member, the size of
8259          * the struct is effectively forced to be a multiple of 4 or 8 bytes
8260          * (respectively) without increasing the size of the struct unless
8261          * necessary.
8262          */
8263         union {
8264                 struct {
8265                         duk_heaphdr hdr;
8266 #if defined(DUK_USE_BUFLEN16)
8267                         /* Stored in duk_heaphdr unused flags. */
8268 #else
8269                         duk_size_t size;
8270 #endif
8271                 } s;
8272 #if (DUK_USE_ALIGN_BY == 4)
8273                 duk_uint32_t dummy_for_align4;
8274 #elif (DUK_USE_ALIGN_BY == 8)
8275                 duk_double_t dummy_for_align8_1;
8276 #if defined(DUK_USE_64BIT_OPS)
8277                 duk_uint64_t dummy_for_align8_2;
8278 #endif
8279 #elif (DUK_USE_ALIGN_BY == 1)
8280                 /* no extra padding */
8281 #else
8282 #error invalid DUK_USE_ALIGN_BY
8283 #endif
8284         } u;
8285
8286         /*
8287          *  Data follows the struct header.  The struct size is padded by the
8288          *  compiler based on the struct members.  This guarantees that the
8289          *  buffer data will be aligned-by-4 but not necessarily aligned-by-8.
8290          *
8291          *  On platforms where alignment does not matter, the struct padding
8292          *  could be removed (if there is any).  On platforms where alignment
8293          *  by 8 is required, the struct size must be forced to be a multiple
8294          *  of 8 by some means.  Without it, some user code may break, and also
8295          *  Duktape itself breaks (e.g. the compiler stores duk_tvals in a
8296          *  dynamic buffer).
8297          */
8298 }
8299 #if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
8300 __attribute__ ((aligned (8)))
8301 #elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
8302 __attribute__ ((aligned (8)))
8303 #endif
8304 ;
8305 #if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
8306 #pragma pack(pop)
8307 #endif
8308
8309 /* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using
8310  * heap allocation primitives.  Also used for external buffers when low memory
8311  * options are not used.
8312  */
8313 struct duk_hbuffer_dynamic {
8314         duk_heaphdr hdr;
8315
8316 #if defined(DUK_USE_BUFLEN16)
8317         /* Stored in duk_heaphdr unused flags. */
8318 #else
8319         duk_size_t size;
8320 #endif
8321
8322 #if defined(DUK_USE_HEAPPTR16)
8323         /* Stored in duk_heaphdr h_extra16. */
8324 #else
8325         void *curr_alloc;  /* may be NULL if alloc_size == 0 */
8326 #endif
8327
8328         /*
8329          *  Allocation size for 'curr_alloc' is alloc_size.  There is no
8330          *  automatic NUL terminator for buffers (see above for rationale).
8331          *
8332          *  'curr_alloc' is explicitly allocated with heap allocation
8333          *  primitives and will thus always have alignment suitable for
8334          *  e.g. duk_tval and an IEEE double.
8335          */
8336 };
8337
8338 /* External buffer with 'curr_alloc' managed by user code and pointing to an
8339  * arbitrary address.  When heap pointer compression is not used, this struct
8340  * has the same layout as duk_hbuffer_dynamic.
8341  */
8342 struct duk_hbuffer_external {
8343         duk_heaphdr hdr;
8344
8345 #if defined(DUK_USE_BUFLEN16)
8346         /* Stored in duk_heaphdr unused flags. */
8347 #else
8348         duk_size_t size;
8349 #endif
8350
8351         /* Cannot be compressed as a heap pointer because may point to
8352          * an arbitrary address.
8353          */
8354         void *curr_alloc;  /* may be NULL if alloc_size == 0 */
8355 };
8356
8357 /*
8358  *  Prototypes
8359  */
8360
8361 DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata);
8362 DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud);  /* indirect allocs */
8363
8364 /* dynamic buffer ops */
8365 DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size);
8366 DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
8367
8368 #endif  /* DUK_HBUFFER_H_INCLUDED */
8369 /* #include duk_hproxy.h */
8370 #line 1 "duk_hproxy.h"
8371 /*
8372  *  Proxy object representation.
8373  */
8374
8375 #if !defined(DUK_HPROXY_H_INCLUDED)
8376 #define DUK_HPROXY_H_INCLUDED
8377
8378 #define DUK_ASSERT_HPROXY_VALID(h) do { \
8379                 DUK_ASSERT((h) != NULL); \
8380                 DUK_ASSERT((h)->target != NULL); \
8381                 DUK_ASSERT((h)->handler != NULL); \
8382                 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ((duk_hobject *) (h))); \
8383         } while (0)
8384
8385 struct duk_hproxy {
8386         /* Shared object part. */
8387         duk_hobject obj;
8388
8389         /* Proxy target object. */
8390         duk_hobject *target;
8391
8392         /* Proxy handlers (traps). */
8393         duk_hobject *handler;
8394 };
8395
8396 #endif  /* DUK_HPROXY_H_INCLUDED */
8397 /* #include duk_heap.h */
8398 #line 1 "duk_heap.h"
8399 /*
8400  *  Heap structure.
8401  *
8402  *  Heap contains allocated heap objects, interned strings, and built-in
8403  *  strings for one or more threads.
8404  */
8405
8406 #if !defined(DUK_HEAP_H_INCLUDED)
8407 #define DUK_HEAP_H_INCLUDED
8408
8409 /* alloc function typedefs in duktape.h */
8410
8411 /*
8412  *  Heap flags
8413  */
8414
8415 #define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED            (1U << 0)  /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
8416 #define DUK_HEAP_FLAG_INTERRUPT_RUNNING                        (1U << 1)  /* executor interrupt running (used to avoid nested interrupts) */
8417 #define DUK_HEAP_FLAG_FINALIZER_NORESCUE                       (1U << 2)  /* heap destruction ongoing, finalizer rescue no longer possible */
8418 #define DUK_HEAP_FLAG_DEBUGGER_PAUSED                          (1U << 3)  /* debugger is paused: talk with debug client until step/resume */
8419
8420 #define DUK__HEAP_HAS_FLAGS(heap,bits)               ((heap)->flags & (bits))
8421 #define DUK__HEAP_SET_FLAGS(heap,bits)  do { \
8422                 (heap)->flags |= (bits); \
8423         } while (0)
8424 #define DUK__HEAP_CLEAR_FLAGS(heap,bits)  do { \
8425                 (heap)->flags &= ~(bits); \
8426         } while (0)
8427
8428 #define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)   DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
8429 #define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap)               DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
8430 #define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)              DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
8431 #define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap)                 DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
8432
8433 #define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap)   DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
8434 #define DUK_HEAP_SET_INTERRUPT_RUNNING(heap)               DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
8435 #define DUK_HEAP_SET_FINALIZER_NORESCUE(heap)              DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
8436 #define DUK_HEAP_SET_DEBUGGER_PAUSED(heap)                 DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
8437
8438 #define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
8439 #define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap)             DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
8440 #define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap)            DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
8441 #define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap)               DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
8442
8443 /*
8444  *  Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
8445  */
8446
8447 #define DUK_LJ_TYPE_UNKNOWN      0    /* unused */
8448 #define DUK_LJ_TYPE_THROW        1    /* value1 -> error object */
8449 #define DUK_LJ_TYPE_YIELD        2    /* value1 -> yield value, iserror -> error / normal */
8450 #define DUK_LJ_TYPE_RESUME       3    /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */
8451 #define DUK_LJ_TYPE_BREAK        4    /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */
8452 #define DUK_LJ_TYPE_CONTINUE     5    /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */
8453 #define DUK_LJ_TYPE_RETURN       6    /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */
8454 #define DUK_LJ_TYPE_NORMAL       7    /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */
8455
8456 /*
8457  *  Mark-and-sweep flags
8458  *
8459  *  These are separate from heap level flags now but could be merged.
8460  *  The heap structure only contains a 'base mark-and-sweep flags'
8461  *  field and the GC caller can impose further flags.
8462  */
8463
8464 /* Emergency mark-and-sweep: try extra hard, even at the cost of
8465  * performance.
8466  */
8467 #define DUK_MS_FLAG_EMERGENCY                (1U << 0)
8468
8469 /* Voluntary mark-and-sweep: triggered periodically. */
8470 #define DUK_MS_FLAG_VOLUNTARY                (1U << 1)
8471
8472 /* Postpone rescue decisions for reachable objects with FINALIZED set.
8473  * Used during finalize_list processing to avoid incorrect rescue
8474  * decisions due to finalize_list being a reachability root.
8475  */
8476 #define DUK_MS_FLAG_POSTPONE_RESCUE          (1U << 2)
8477
8478 /* Don't compact objects; needed during object property table resize
8479  * to prevent a recursive resize.  It would suffice to protect only the
8480  * current object being resized, but this is not yet implemented.
8481  */
8482 #define DUK_MS_FLAG_NO_OBJECT_COMPACTION     (1U << 3)
8483
8484 /*
8485  *  Thread switching
8486  *
8487  *  To switch heap->curr_thread, use the macro below so that interrupt counters
8488  *  get updated correctly.  The macro allows a NULL target thread because that
8489  *  happens e.g. in call handling.
8490  */
8491
8492 #if defined(DUK_USE_INTERRUPT_COUNTER)
8493 #define DUK_HEAP_SWITCH_THREAD(heap,newthr)  duk_heap_switch_thread((heap), (newthr))
8494 #else
8495 #define DUK_HEAP_SWITCH_THREAD(heap,newthr)  do { \
8496                 (heap)->curr_thread = (newthr); \
8497         } while (0)
8498 #endif
8499
8500 /*
8501  *  Stats
8502  */
8503
8504 #if defined(DUK_USE_DEBUG)
8505 #define DUK_STATS_INC(heap,fieldname) do { \
8506                 (heap)->fieldname += 1; \
8507         } while (0)
8508 #else
8509 #define DUK_STATS_INC(heap,fieldname) do {} while (0)
8510 #endif
8511
8512 /*
8513  *  Other heap related defines
8514  */
8515
8516 /* Mark-and-sweep interval is relative to combined count of objects and
8517  * strings kept in the heap during the latest mark-and-sweep pass.
8518  * Fixed point .8 multiplier and .0 adder.  Trigger count (interval) is
8519  * decreased by each (re)allocation attempt (regardless of size), and each
8520  * refzero processed object.
8521  *
8522  * 'SKIP' indicates how many (re)allocations to wait until a retry if
8523  * GC is skipped because there is no thread do it with yet (happens
8524  * only during init phases).
8525  */
8526 #if defined(DUK_USE_REFERENCE_COUNTING)
8527 #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT              12800L  /* 50x heap size */
8528 #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD               1024L
8529 #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP              256L
8530 #else
8531 #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT              256L    /* 1x heap size */
8532 #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD               1024L
8533 #define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP              256L
8534 #endif
8535
8536 /* GC torture. */
8537 #if defined(DUK_USE_GC_TORTURE)
8538 #define DUK_GC_TORTURE(heap) do { duk_heap_mark_and_sweep((heap), 0); } while (0)
8539 #else
8540 #define DUK_GC_TORTURE(heap) do { } while (0)
8541 #endif
8542
8543 /* Stringcache is used for speeding up char-offset-to-byte-offset
8544  * translations for non-ASCII strings.
8545  */
8546 #define DUK_HEAP_STRCACHE_SIZE                            4
8547 #define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT                16  /* strings up to the this length are not cached */
8548
8549 /* Some list management macros. */
8550 #define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr)     duk_heap_insert_into_heap_allocated((heap), (hdr))
8551 #if defined(DUK_USE_REFERENCE_COUNTING)
8552 #define DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap,hdr)     duk_heap_remove_from_heap_allocated((heap), (hdr))
8553 #endif
8554 #if defined(DUK_USE_FINALIZER_SUPPORT)
8555 #define DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap,hdr)      duk_heap_insert_into_finalize_list((heap), (hdr))
8556 #define DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap,hdr)      duk_heap_remove_from_finalize_list((heap), (hdr))
8557 #endif
8558
8559 /*
8560  *  Built-in strings
8561  */
8562
8563 /* heap string indices are autogenerated in duk_strings.h */
8564 #if defined(DUK_USE_ROM_STRINGS)
8565 #define DUK_HEAP_GET_STRING(heap,idx) \
8566         ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
8567 #else  /* DUK_USE_ROM_STRINGS */
8568 #if defined(DUK_USE_HEAPPTR16)
8569 #define DUK_HEAP_GET_STRING(heap,idx) \
8570         ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)]))
8571 #else
8572 #define DUK_HEAP_GET_STRING(heap,idx) \
8573         ((heap)->strs[(idx)])
8574 #endif
8575 #endif  /* DUK_USE_ROM_STRINGS */
8576
8577 /*
8578  *  Raw memory calls: relative to heap, but no GC interaction
8579  */
8580
8581 #define DUK_ALLOC_RAW(heap,size) \
8582         ((heap)->alloc_func((heap)->heap_udata, (size)))
8583
8584 #define DUK_REALLOC_RAW(heap,ptr,newsize) \
8585         ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize)))
8586
8587 #define DUK_FREE_RAW(heap,ptr) \
8588         ((heap)->free_func((heap)->heap_udata, (void *) (ptr)))
8589
8590 /*
8591  *  Memory calls: relative to heap, GC interaction, but no error throwing.
8592  *
8593  *  XXX: Currently a mark-and-sweep triggered by memory allocation will run
8594  *  using the heap->heap_thread.  This thread is also used for running
8595  *  mark-and-sweep finalization; this is not ideal because it breaks the
8596  *  isolation between multiple global environments.
8597  *
8598  *  Notes:
8599  *
8600  *    - DUK_FREE() is required to ignore NULL and any other possible return
8601  *      value of a zero-sized alloc/realloc (same as ANSI C free()).
8602  *
8603  *    - There is no DUK_REALLOC_ZEROED because we don't assume to know the
8604  *      old size.  Caller must zero the reallocated memory.
8605  *
8606  *    - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered
8607  *      by an allocation failure might invalidate the original 'ptr', thus
8608  *      causing a realloc retry to use an invalid pointer.  Example: we're
8609  *      reallocating the value stack and a finalizer resizes the same value
8610  *      stack during mark-and-sweep.  The indirect variant requests for the
8611  *      current location of the pointer being reallocated using a callback
8612  *      right before every realloc attempt; this circuitous approach is used
8613  *      to avoid strict aliasing issues in a more straightforward indirect
8614  *      pointer (void **) approach.  Note: the pointer in the storage
8615  *      location is read but is NOT updated; the caller must do that.
8616  */
8617
8618 /* callback for indirect reallocs, request for current pointer */
8619 typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
8620
8621 #define DUK_ALLOC(heap,size)                            duk_heap_mem_alloc((heap), (size))
8622 #define DUK_ALLOC_ZEROED(heap,size)                     duk_heap_mem_alloc_zeroed((heap), (size))
8623 #define DUK_REALLOC(heap,ptr,newsize)                   duk_heap_mem_realloc((heap), (ptr), (newsize))
8624 #define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize)        duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
8625 #define DUK_FREE(heap,ptr)                              duk_heap_mem_free((heap), (ptr))
8626
8627 /*
8628  *  Checked allocation, relative to a thread
8629  *
8630  *  DUK_FREE_CHECKED() doesn't actually throw, but accepts a 'thr' argument
8631  *  for convenience.
8632  */
8633
8634 #define DUK_ALLOC_CHECKED(thr,size)                     duk_heap_mem_alloc_checked((thr), (size))
8635 #define DUK_ALLOC_CHECKED_ZEROED(thr,size)              duk_heap_mem_alloc_checked_zeroed((thr), (size))
8636 #define DUK_FREE_CHECKED(thr,ptr)                       duk_heap_mem_free((thr)->heap, (ptr))
8637
8638 /*
8639  *  Memory constants
8640  */
8641
8642 #define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT           10  /* Retry allocation after mark-and-sweep for this
8643                                                               * many times.  A single mark-and-sweep round is
8644                                                               * not guaranteed to free all unreferenced memory
8645                                                               * because of finalization (in fact, ANY number of
8646                                                               * rounds is strictly not enough).
8647                                                               */
8648
8649 #define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT  3  /* Starting from this round, use emergency mode
8650                                                               * for mark-and-sweep.
8651                                                               */
8652
8653 /*
8654  *  Debugger support
8655  */
8656
8657 /* Maximum number of breakpoints.  Only breakpoints that are set are
8658  * consulted so increasing this has no performance impact.
8659  */
8660 #define DUK_HEAP_MAX_BREAKPOINTS          16
8661
8662 /* Opcode interval for a Date-based status/peek rate limit check.  Only
8663  * relevant when debugger is attached.  Requesting a timestamp may be a
8664  * slow operation on some platforms so this shouldn't be too low.  On the
8665  * other hand a high value makes Duktape react to a pause request slowly.
8666  */
8667 #define DUK_HEAP_DBG_RATELIMIT_OPCODES    4000
8668
8669 /* Milliseconds between status notify and transport peeks. */
8670 #define DUK_HEAP_DBG_RATELIMIT_MILLISECS  200
8671
8672 /* Debugger pause flags. */
8673 #define DUK_PAUSE_FLAG_ONE_OPCODE        (1U << 0)   /* pause when a single opcode has been executed */
8674 #define DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE (1U << 1)   /* one opcode pause actually active; artifact of current implementation */
8675 #define DUK_PAUSE_FLAG_LINE_CHANGE       (1U << 2)   /* pause when current line number changes */
8676 #define DUK_PAUSE_FLAG_FUNC_ENTRY        (1U << 3)   /* pause when entering a function */
8677 #define DUK_PAUSE_FLAG_FUNC_EXIT         (1U << 4)   /* pause when exiting current function */
8678 #define DUK_PAUSE_FLAG_CAUGHT_ERROR      (1U << 5)   /* pause when about to throw an error that is caught */
8679 #define DUK_PAUSE_FLAG_UNCAUGHT_ERROR    (1U << 6)   /* pause when about to throw an error that won't be caught */
8680
8681 struct duk_breakpoint {
8682         duk_hstring *filename;
8683         duk_uint32_t line;
8684 };
8685
8686 /*
8687  *  String cache should ideally be at duk_hthread level, but that would
8688  *  cause string finalization to slow down relative to the number of
8689  *  threads; string finalization must check the string cache for "weak"
8690  *  references to the string being finalized to avoid dead pointers.
8691  *
8692  *  Thus, string caches are now at the heap level now.
8693  */
8694
8695 struct duk_strcache_entry {
8696         duk_hstring *h;
8697         duk_uint32_t bidx;
8698         duk_uint32_t cidx;
8699 };
8700
8701 /*
8702  *  Longjmp state, contains the information needed to perform a longjmp.
8703  *  Longjmp related values are written to value1, value2, and iserror.
8704  */
8705
8706 struct duk_ljstate {
8707         duk_jmpbuf *jmpbuf_ptr;   /* current setjmp() catchpoint */
8708         duk_small_uint_t type;    /* longjmp type */
8709         duk_bool_t iserror;       /* isError flag for yield */
8710         duk_tval value1;          /* 1st related value (type specific) */
8711         duk_tval value2;          /* 2nd related value (type specific) */
8712 };
8713
8714 #define DUK_ASSERT_LJSTATE_UNSET(heap) do { \
8715                 DUK_ASSERT(heap != NULL); \
8716                 DUK_ASSERT(heap->lj.type == DUK_LJ_TYPE_UNKNOWN); \
8717                 DUK_ASSERT(heap->lj.iserror == 0); \
8718                 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value1)); \
8719                 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&heap->lj.value2)); \
8720         } while (0)
8721 #define DUK_ASSERT_LJSTATE_SET(heap) do { \
8722                 DUK_ASSERT(heap != NULL); \
8723                 DUK_ASSERT(heap->lj.type != DUK_LJ_TYPE_UNKNOWN); \
8724         } while (0)
8725
8726 /*
8727  *  Literal intern cache
8728  */
8729
8730 struct duk_litcache_entry {
8731         const duk_uint8_t *addr;
8732         duk_hstring *h;
8733 };
8734
8735 /*
8736  *  Main heap structure
8737  */
8738
8739 struct duk_heap {
8740         duk_small_uint_t flags;
8741
8742         /* Allocator functions. */
8743         duk_alloc_function alloc_func;
8744         duk_realloc_function realloc_func;
8745         duk_free_function free_func;
8746
8747         /* Heap udata, used for allocator functions but also for other heap
8748          * level callbacks like fatal function, pointer compression, etc.
8749          */
8750         void *heap_udata;
8751
8752         /* Fatal error handling, called e.g. when a longjmp() is needed but
8753          * lj.jmpbuf_ptr is NULL.  fatal_func must never return; it's not
8754          * declared as "noreturn" because doing that for typedefs is a bit
8755          * challenging portability-wise.
8756          */
8757         duk_fatal_function fatal_func;
8758
8759         /* Main list of allocated heap objects.  Objects are either here,
8760          * in finalize_list waiting for processing, or in refzero_list
8761          * temporarily while a DECREF refzero cascade finishes.
8762          */
8763         duk_heaphdr *heap_allocated;
8764
8765         /* Temporary work list for freeing a cascade of objects when a DECREF
8766          * (or DECREF_NORZ) encounters a zero refcount.  Using a work list
8767          * allows fixed C stack size when refcounts go to zero for a chain of
8768          * objects.  Outside of DECREF this is always a NULL because DECREF is
8769          * processed without side effects (only memory free calls).
8770          */
8771 #if defined(DUK_USE_REFERENCE_COUNTING)
8772         duk_heaphdr *refzero_list;
8773 #endif
8774
8775 #if defined(DUK_USE_FINALIZER_SUPPORT)
8776         /* Work list for objects to be finalized. */
8777         duk_heaphdr *finalize_list;
8778 #if defined(DUK_USE_ASSERTIONS)
8779         /* Object whose finalizer is executing right now (no nesting). */
8780         duk_heaphdr *currently_finalizing;
8781 #endif
8782 #endif
8783
8784         /* Freelist for duk_activations and duk_catchers. */
8785 #if defined(DUK_USE_CACHE_ACTIVATION)
8786         duk_activation *activation_free;
8787 #endif
8788 #if defined(DUK_USE_CACHE_CATCHER)
8789         duk_catcher *catcher_free;
8790 #endif
8791
8792         /* Voluntary mark-and-sweep trigger counter.  Intentionally signed
8793          * because we continue decreasing the value when voluntary GC cannot
8794          * run.
8795          */
8796 #if defined(DUK_USE_VOLUNTARY_GC)
8797         duk_int_t ms_trigger_counter;
8798 #endif
8799
8800         /* Mark-and-sweep recursion control: too deep recursion causes
8801          * multi-pass processing to avoid growing C stack without bound.
8802          */
8803         duk_uint_t ms_recursion_depth;
8804
8805         /* Mark-and-sweep flags automatically active (used for critical sections). */
8806         duk_small_uint_t ms_base_flags;
8807
8808         /* Mark-and-sweep running flag.  Prevents re-entry, and also causes
8809          * refzero events to be ignored (= objects won't be queued to refzero_list).
8810          */
8811         duk_uint_t ms_running;
8812
8813         /* Mark-and-sweep prevent count, stacking.  Used to avoid M&S side
8814          * effects (besides finalizers which are controlled separately) such
8815          * as compacting the string table or object property tables.  This
8816          * is also bumped when ms_running is set to prevent recursive re-entry.
8817          * Can also be bumped when mark-and-sweep is not running.
8818          */
8819         duk_uint_t ms_prevent_count;
8820
8821         /* Finalizer processing prevent count, stacking.  Bumped when finalizers
8822          * are processed to prevent recursive finalizer processing (first call site
8823          * processing finalizers handles all finalizers until the list is empty).
8824          * Can also be bumped explicitly to prevent finalizer execution.
8825          */
8826         duk_uint_t pf_prevent_count;
8827
8828         /* When processing finalize_list, don't actually run finalizers but
8829          * queue finalizable objects back to heap_allocated as is.  This is
8830          * used during heap destruction to deal with finalizers that keep
8831          * on creating more finalizable garbage.
8832          */
8833         duk_uint_t pf_skip_finalizers;
8834
8835 #if defined(DUK_USE_ASSERTIONS)
8836         /* Set when we're in a critical path where an error throw would cause
8837          * e.g. sandboxing/protected call violations or state corruption.  This
8838          * is just used for asserts.
8839          */
8840         duk_bool_t error_not_allowed;
8841 #endif
8842
8843 #if defined(DUK_USE_ASSERTIONS)
8844         /* Set when heap is still being initialized, helps with writing
8845          * some assertions.
8846          */
8847         duk_bool_t heap_initializing;
8848 #endif
8849
8850         /* Marker for detecting internal "double faults", errors thrown when
8851          * we're trying to create an error object, see duk_error_throw.c.
8852          */
8853         duk_bool_t creating_error;
8854
8855         /* Marker for indicating we're calling a user error augmentation
8856          * (errCreate/errThrow) function.  Errors created/thrown during
8857          * such a call are not augmented.
8858          */
8859 #if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
8860         duk_bool_t augmenting_error;
8861 #endif
8862
8863         /* Longjmp state. */
8864         duk_ljstate lj;
8865
8866         /* Heap thread, used internally and for finalization. */
8867         duk_hthread *heap_thread;
8868
8869         /* Current running thread. */
8870         duk_hthread *curr_thread;
8871
8872         /* Heap level "stash" object (e.g., various reachability roots). */
8873         duk_hobject *heap_object;
8874
8875         /* duk_handle_call / duk_handle_safe_call recursion depth limiting */
8876         duk_int_t call_recursion_depth;
8877         duk_int_t call_recursion_limit;
8878
8879         /* Mix-in value for computing string hashes; should be reasonably unpredictable. */
8880         duk_uint32_t hash_seed;
8881
8882         /* Random number state for duk_util_tinyrandom.c. */
8883 #if !defined(DUK_USE_GET_RANDOM_DOUBLE)
8884 #if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
8885         duk_uint32_t rnd_state;  /* State for Shamir's three-op algorithm */
8886 #else
8887         duk_uint64_t rnd_state[2];  /* State for xoroshiro128+ */
8888 #endif
8889 #endif
8890
8891         /* Counter for unique local symbol creation. */
8892         /* XXX: When 64-bit types are available, it would be more efficient to
8893          * use a duk_uint64_t at least for incrementing but maybe also for
8894          * string formatting in the Symbol constructor.
8895          */
8896         duk_uint32_t sym_counter[2];
8897
8898         /* For manual debugging: instruction count based on executor and
8899          * interrupt counter book-keeping.  Inspect debug logs to see how
8900          * they match up.
8901          */
8902 #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
8903         duk_int_t inst_count_exec;
8904         duk_int_t inst_count_interrupt;
8905 #endif
8906
8907         /* Debugger state. */
8908 #if defined(DUK_USE_DEBUGGER_SUPPORT)
8909         /* Callbacks and udata; dbg_read_cb != NULL is used to indicate attached state. */
8910         duk_debug_read_function dbg_read_cb;                /* required, NULL implies detached */
8911         duk_debug_write_function dbg_write_cb;              /* required */
8912         duk_debug_peek_function dbg_peek_cb;
8913         duk_debug_read_flush_function dbg_read_flush_cb;
8914         duk_debug_write_flush_function dbg_write_flush_cb;
8915         duk_debug_request_function dbg_request_cb;
8916         duk_debug_detached_function dbg_detached_cb;
8917         void *dbg_udata;
8918
8919         /* The following are only relevant when debugger is attached. */
8920         duk_bool_t dbg_processing;              /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
8921         duk_bool_t dbg_state_dirty;             /* resend state next time executor is about to run */
8922         duk_bool_t dbg_force_restart;           /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
8923         duk_bool_t dbg_detaching;               /* debugger detaching; used to avoid calling detach handler recursively */
8924         duk_small_uint_t dbg_pause_flags;       /* flags for automatic pause behavior */
8925         duk_activation *dbg_pause_act;          /* activation related to pause behavior (pause on line change, function entry/exit) */
8926         duk_uint32_t dbg_pause_startline;       /* starting line number for line change related pause behavior */
8927         duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS];  /* breakpoints: [0,breakpoint_count[ gc reachable */
8928         duk_small_uint_t dbg_breakpoint_count;
8929         duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1];  /* currently active breakpoints: NULL term, borrowed pointers */
8930         /* XXX: make active breakpoints actual copies instead of pointers? */
8931
8932         /* These are for rate limiting Status notifications and transport peeking. */
8933         duk_uint_t dbg_exec_counter;            /* cumulative opcode execution count (overflows are OK) */
8934         duk_uint_t dbg_last_counter;            /* value of dbg_exec_counter when we last did a Date-based check */
8935         duk_double_t dbg_last_time;             /* time when status/peek was last done (Date-based rate limit) */
8936
8937         /* Used to support single-byte stream lookahead. */
8938         duk_bool_t dbg_have_next_byte;
8939         duk_uint8_t dbg_next_byte;
8940 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
8941 #if defined(DUK_USE_ASSERTIONS)
8942         duk_bool_t dbg_calling_transport;       /* transport call in progress, calling into Duktape forbidden */
8943 #endif
8944
8945         /* String intern table (weak refs). */
8946 #if defined(DUK_USE_STRTAB_PTRCOMP)
8947         duk_uint16_t *strtable16;
8948 #else
8949         duk_hstring **strtable;
8950 #endif
8951         duk_uint32_t st_mask;    /* mask for lookup, st_size - 1 */
8952         duk_uint32_t st_size;    /* stringtable size */
8953 #if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE)
8954         duk_uint32_t st_count;   /* string count for resize load factor checks */
8955 #endif
8956         duk_bool_t st_resizing;  /* string table is being resized; avoid recursive resize */
8957
8958         /* String access cache (codepoint offset -> byte offset) for fast string
8959          * character looping; 'weak' reference which needs special handling in GC.
8960          */
8961         duk_strcache_entry strcache[DUK_HEAP_STRCACHE_SIZE];
8962
8963 #if defined(DUK_USE_LITCACHE_SIZE)
8964         /* Literal intern cache.  When enabled, strings interned as literals
8965          * (e.g. duk_push_literal()) will be pinned and cached for the lifetime
8966          * of the heap.
8967          */
8968         duk_litcache_entry litcache[DUK_USE_LITCACHE_SIZE];
8969 #endif
8970
8971         /* Built-in strings. */
8972 #if defined(DUK_USE_ROM_STRINGS)
8973         /* No field needed when strings are in ROM. */
8974 #else
8975 #if defined(DUK_USE_HEAPPTR16)
8976         duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS];
8977 #else
8978         duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
8979 #endif
8980 #endif
8981
8982         /* Stats. */
8983 #if defined(DUK_USE_DEBUG)
8984         duk_int_t stats_exec_opcodes;
8985         duk_int_t stats_exec_interrupt;
8986         duk_int_t stats_exec_throw;
8987         duk_int_t stats_call_all;
8988         duk_int_t stats_call_tailcall;
8989         duk_int_t stats_call_ecmatoecma;
8990         duk_int_t stats_safecall_all;
8991         duk_int_t stats_safecall_nothrow;
8992         duk_int_t stats_safecall_throw;
8993         duk_int_t stats_ms_try_count;
8994         duk_int_t stats_ms_skip_count;
8995         duk_int_t stats_ms_emergency_count;
8996         duk_int_t stats_strtab_intern_hit;
8997         duk_int_t stats_strtab_intern_miss;
8998         duk_int_t stats_strtab_resize_check;
8999         duk_int_t stats_strtab_resize_grow;
9000         duk_int_t stats_strtab_resize_shrink;
9001         duk_int_t stats_strtab_litcache_hit;
9002         duk_int_t stats_strtab_litcache_miss;
9003         duk_int_t stats_strtab_litcache_pin;
9004         duk_int_t stats_object_realloc_props;
9005         duk_int_t stats_object_abandon_array;
9006         duk_int_t stats_getownpropdesc_count;
9007         duk_int_t stats_getownpropdesc_hit;
9008         duk_int_t stats_getownpropdesc_miss;
9009         duk_int_t stats_getpropdesc_count;
9010         duk_int_t stats_getpropdesc_hit;
9011         duk_int_t stats_getpropdesc_miss;
9012         duk_int_t stats_getprop_all;
9013         duk_int_t stats_getprop_arrayidx;
9014         duk_int_t stats_getprop_bufobjidx;
9015         duk_int_t stats_getprop_bufferidx;
9016         duk_int_t stats_getprop_bufferlen;
9017         duk_int_t stats_getprop_stringidx;
9018         duk_int_t stats_getprop_stringlen;
9019         duk_int_t stats_getprop_proxy;
9020         duk_int_t stats_getprop_arguments;
9021         duk_int_t stats_putprop_all;
9022         duk_int_t stats_putprop_arrayidx;
9023         duk_int_t stats_putprop_bufobjidx;
9024         duk_int_t stats_putprop_bufferidx;
9025         duk_int_t stats_putprop_proxy;
9026         duk_int_t stats_getvar_all;
9027         duk_int_t stats_putvar_all;
9028 #endif
9029 };
9030
9031 /*
9032  *  Prototypes
9033  */
9034
9035 DUK_INTERNAL_DECL
9036 duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
9037                          duk_realloc_function realloc_func,
9038                          duk_free_function free_func,
9039                          void *heap_udata,
9040                          duk_fatal_function fatal_func);
9041 DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
9042 DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h);
9043 DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h);
9044 DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h);
9045 DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
9046
9047 DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
9048 #if defined(DUK_USE_REFERENCE_COUNTING)
9049 DUK_INTERNAL_DECL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
9050 #endif
9051 #if defined(DUK_USE_FINALIZER_SUPPORT)
9052 DUK_INTERNAL_DECL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
9053 DUK_INTERNAL_DECL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr);
9054 #endif
9055 #if defined(DUK_USE_ASSERTIONS)
9056 DUK_INTERNAL_DECL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr);
9057 #endif
9058 #if defined(DUK_USE_INTERRUPT_COUNTER)
9059 DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
9060 #endif
9061
9062 DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
9063 DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
9064 #if defined(DUK_USE_LITCACHE_SIZE)
9065 DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen);
9066 #endif
9067 DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val);
9068 DUK_INTERNAL_DECL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
9069 #if defined(DUK_USE_REFERENCE_COUNTING)
9070 DUK_INTERNAL_DECL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h);
9071 #endif
9072 DUK_INTERNAL_DECL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev);
9073 DUK_INTERNAL_DECL void duk_heap_strtable_force_resize(duk_heap *heap);
9074 DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap);
9075 #if defined(DUK_USE_DEBUG)
9076 DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap);
9077 #endif
9078
9079 DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
9080 DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
9081
9082 #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
9083 DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size);
9084 DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize);
9085 DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
9086 #endif
9087
9088 DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
9089 DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
9090 DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size);
9091 DUK_INTERNAL_DECL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size);
9092 DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
9093 DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
9094 DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
9095
9096 DUK_INTERNAL_DECL void duk_heap_free_freelists(duk_heap *heap);
9097
9098 #if defined(DUK_USE_FINALIZER_SUPPORT)
9099 DUK_INTERNAL_DECL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj);
9100 DUK_INTERNAL_DECL void duk_heap_process_finalize_list(duk_heap *heap);
9101 #endif  /* DUK_USE_FINALIZER_SUPPORT */
9102
9103 DUK_INTERNAL_DECL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
9104
9105 DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
9106
9107 #endif  /* DUK_HEAP_H_INCLUDED */
9108 /* #include duk_debugger.h */
9109 #line 1 "duk_debugger.h"
9110 #if !defined(DUK_DEBUGGER_H_INCLUDED)
9111 #define DUK_DEBUGGER_H_INCLUDED
9112
9113 /* Debugger protocol version is defined in the public API header. */
9114
9115 /* Initial bytes for markers. */
9116 #define DUK_DBG_IB_EOM                   0x00
9117 #define DUK_DBG_IB_REQUEST               0x01
9118 #define DUK_DBG_IB_REPLY                 0x02
9119 #define DUK_DBG_IB_ERROR                 0x03
9120 #define DUK_DBG_IB_NOTIFY                0x04
9121
9122 /* Other initial bytes. */
9123 #define DUK_DBG_IB_INT4                  0x10
9124 #define DUK_DBG_IB_STR4                  0x11
9125 #define DUK_DBG_IB_STR2                  0x12
9126 #define DUK_DBG_IB_BUF4                  0x13
9127 #define DUK_DBG_IB_BUF2                  0x14
9128 #define DUK_DBG_IB_UNUSED                0x15
9129 #define DUK_DBG_IB_UNDEFINED             0x16
9130 #define DUK_DBG_IB_NULL                  0x17
9131 #define DUK_DBG_IB_TRUE                  0x18
9132 #define DUK_DBG_IB_FALSE                 0x19
9133 #define DUK_DBG_IB_NUMBER                0x1a
9134 #define DUK_DBG_IB_OBJECT                0x1b
9135 #define DUK_DBG_IB_POINTER               0x1c
9136 #define DUK_DBG_IB_LIGHTFUNC             0x1d
9137 #define DUK_DBG_IB_HEAPPTR               0x1e
9138 /* The short string/integer initial bytes starting from 0x60 don't have
9139  * defines now.
9140  */
9141
9142 /* Error codes. */
9143 #define DUK_DBG_ERR_UNKNOWN              0x00
9144 #define DUK_DBG_ERR_UNSUPPORTED          0x01
9145 #define DUK_DBG_ERR_TOOMANY              0x02
9146 #define DUK_DBG_ERR_NOTFOUND             0x03
9147 #define DUK_DBG_ERR_APPLICATION          0x04
9148
9149 /* Commands and notifys initiated by Duktape. */
9150 #define DUK_DBG_CMD_STATUS               0x01
9151 #define DUK_DBG_CMD_UNUSED_2             0x02  /* Duktape 1.x: print notify */
9152 #define DUK_DBG_CMD_UNUSED_3             0x03  /* Duktape 1.x: alert notify */
9153 #define DUK_DBG_CMD_UNUSED_4             0x04  /* Duktape 1.x: log notify */
9154 #define DUK_DBG_CMD_THROW                0x05
9155 #define DUK_DBG_CMD_DETACHING            0x06
9156 #define DUK_DBG_CMD_APPNOTIFY            0x07
9157
9158 /* Commands initiated by debug client. */
9159 #define DUK_DBG_CMD_BASICINFO            0x10
9160 #define DUK_DBG_CMD_TRIGGERSTATUS        0x11
9161 #define DUK_DBG_CMD_PAUSE                0x12
9162 #define DUK_DBG_CMD_RESUME               0x13
9163 #define DUK_DBG_CMD_STEPINTO             0x14
9164 #define DUK_DBG_CMD_STEPOVER             0x15
9165 #define DUK_DBG_CMD_STEPOUT              0x16
9166 #define DUK_DBG_CMD_LISTBREAK            0x17
9167 #define DUK_DBG_CMD_ADDBREAK             0x18
9168 #define DUK_DBG_CMD_DELBREAK             0x19
9169 #define DUK_DBG_CMD_GETVAR               0x1a
9170 #define DUK_DBG_CMD_PUTVAR               0x1b
9171 #define DUK_DBG_CMD_GETCALLSTACK         0x1c
9172 #define DUK_DBG_CMD_GETLOCALS            0x1d
9173 #define DUK_DBG_CMD_EVAL                 0x1e
9174 #define DUK_DBG_CMD_DETACH               0x1f
9175 #define DUK_DBG_CMD_DUMPHEAP             0x20
9176 #define DUK_DBG_CMD_GETBYTECODE          0x21
9177 #define DUK_DBG_CMD_APPREQUEST           0x22
9178 #define DUK_DBG_CMD_GETHEAPOBJINFO       0x23
9179 #define DUK_DBG_CMD_GETOBJPROPDESC       0x24
9180 #define DUK_DBG_CMD_GETOBJPROPDESCRANGE  0x25
9181
9182 /* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
9183  * The remaining flags are specific to the debugger.
9184  */
9185 #define DUK_DBG_PROPFLAG_SYMBOL          (1U << 8)
9186 #define DUK_DBG_PROPFLAG_HIDDEN          (1U << 9)
9187
9188 #if defined(DUK_USE_DEBUGGER_SUPPORT)
9189 DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
9190
9191 DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr);
9192 DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr);
9193
9194 DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length);
9195 DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr);
9196
9197 DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length);
9198 DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr);
9199 DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr);
9200 DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr);
9201 /* XXX: exposed duk_debug_read_pointer */
9202 /* XXX: exposed duk_debug_read_buffer */
9203 /* XXX: exposed duk_debug_read_hbuffer */
9204 #if 0
9205 DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr);
9206 #endif
9207 #if defined(DUK_USE_DEBUGGER_INSPECT)
9208 DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr);
9209 #endif
9210 DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr);
9211
9212 DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length);
9213 DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x);
9214 DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
9215 DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr);
9216 #if defined(DUK_USE_DEBUGGER_INSPECT)
9217 DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr);
9218 #endif
9219 DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val);
9220 DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x);
9221 DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x);
9222 DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length);
9223 DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data);
9224 DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h);
9225 DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length);
9226 DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h);
9227 DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr);
9228 #if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
9229 DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
9230 #endif
9231 DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj);
9232 DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv);
9233 #if 0  /* unused */
9234 DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command);
9235 #endif
9236 DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr);
9237 DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg);
9238 DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command);
9239 DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
9240
9241 DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
9242 DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr);
9243 #if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
9244 DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal);
9245 #endif
9246
9247 DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc);
9248 DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
9249
9250 DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
9251 DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
9252
9253 DUK_INTERNAL_DECL duk_bool_t duk_debug_is_attached(duk_heap *heap);
9254 DUK_INTERNAL_DECL duk_bool_t duk_debug_is_paused(duk_heap *heap);
9255 DUK_INTERNAL_DECL void duk_debug_set_paused(duk_heap *heap);
9256 DUK_INTERNAL_DECL void duk_debug_clear_paused(duk_heap *heap);
9257 DUK_INTERNAL_DECL void duk_debug_clear_pause_state(duk_heap *heap);
9258 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
9259
9260 #endif  /* DUK_DEBUGGER_H_INCLUDED */
9261 /* #include duk_debug.h */
9262 #line 1 "duk_debug.h"
9263 /*
9264  *  Debugging macros, DUK_DPRINT() and its variants in particular.
9265  *
9266  *  DUK_DPRINT() allows formatted debug prints, and supports standard
9267  *  and Duktape specific formatters.  See duk_debug_vsnprintf.c for details.
9268  *
9269  *  DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros
9270  *  for technical reasons.  They are concretely used to hide 'x' from the
9271  *  compiler when the corresponding log level is disabled.  This allows
9272  *  clean builds on non-C99 compilers, at the cost of more verbose code.
9273  *  Examples:
9274  *
9275  *    DUK_D(DUK_DPRINT("foo"));
9276  *    DUK_DD(DUK_DDPRINT("foo"));
9277  *    DUK_DDD(DUK_DDDPRINT("foo"));
9278  *
9279  *  This approach is preferable to the old "double parentheses" hack because
9280  *  double parentheses make the C99 solution worse: __FILE__ and __LINE__ can
9281  *  no longer be added transparently without going through globals, which
9282  *  works poorly with threading.
9283  */
9284
9285 #if !defined(DUK_DEBUG_H_INCLUDED)
9286 #define DUK_DEBUG_H_INCLUDED
9287
9288 #if defined(DUK_USE_DEBUG)
9289
9290 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
9291 #define DUK_D(x) x
9292 #else
9293 #define DUK_D(x) do { } while (0) /* omit */
9294 #endif
9295
9296 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
9297 #define DUK_DD(x) x
9298 #else
9299 #define DUK_DD(x) do { } while (0) /* omit */
9300 #endif
9301
9302 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
9303 #define DUK_DDD(x) x
9304 #else
9305 #define DUK_DDD(x) do { } while (0) /* omit */
9306 #endif
9307
9308 /*
9309  *  Exposed debug macros: debugging enabled
9310  */
9311
9312 #if defined(DUK_USE_VARIADIC_MACROS)
9313
9314 /* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
9315  * possible compile time, but waste some space with shared function names.
9316  */
9317 #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__);
9318
9319 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
9320 #define DUK_DPRINT(...)          DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
9321 #else
9322 #define DUK_DPRINT(...)
9323 #endif
9324
9325 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
9326 #define DUK_DDPRINT(...)         DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
9327 #else
9328 #define DUK_DDPRINT(...)
9329 #endif
9330
9331 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
9332 #define DUK_DDDPRINT(...)        DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
9333 #else
9334 #define DUK_DDDPRINT(...)
9335 #endif
9336
9337 #else  /* DUK_USE_VARIADIC_MACROS */
9338
9339 #define DUK__DEBUG_STASH(lev)    \
9340         (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
9341         (void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
9342         (void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \
9343         (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
9344         (void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
9345         (void) (duk_debug_level_stash = (lev))
9346
9347 /* Without variadic macros resort to comma expression trickery to handle debug
9348  * prints.  This generates a lot of harmless warnings.  These hacks are not
9349  * needed normally because DUK_D() and friends will hide the entire debug log
9350  * statement from the compiler.
9351  */
9352
9353 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
9354 #define DUK_DPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log  /* args go here in parens */
9355 #else
9356 #define DUK_DPRINT  0 && /* args go here as a comma expression in parens */
9357 #endif
9358
9359 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
9360 #define DUK_DDPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log  /* args go here in parens */
9361 #else
9362 #define DUK_DDPRINT  0 && /* args */
9363 #endif
9364
9365 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
9366 #define DUK_DDDPRINT  DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log  /* args go here in parens */
9367 #else
9368 #define DUK_DDDPRINT  0 && /* args */
9369 #endif
9370
9371 #endif  /* DUK_USE_VARIADIC_MACROS */
9372
9373 #else  /* DUK_USE_DEBUG */
9374
9375 /*
9376  *  Exposed debug macros: debugging disabled
9377  */
9378
9379 #define DUK_D(x) do { } while (0) /* omit */
9380 #define DUK_DD(x) do { } while (0) /* omit */
9381 #define DUK_DDD(x) do { } while (0) /* omit */
9382
9383 #if defined(DUK_USE_VARIADIC_MACROS)
9384
9385 #define DUK_DPRINT(...)
9386 #define DUK_DDPRINT(...)
9387 #define DUK_DDDPRINT(...)
9388
9389 #else  /* DUK_USE_VARIADIC_MACROS */
9390
9391 #define DUK_DPRINT    0 && /* args go here as a comma expression in parens */
9392 #define DUK_DDPRINT   0 && /* args */
9393 #define DUK_DDDPRINT  0 && /* args */
9394
9395 #endif  /* DUK_USE_VARIADIC_MACROS */
9396
9397 #endif  /* DUK_USE_DEBUG */
9398
9399 /*
9400  *  Structs
9401  */
9402
9403 #if defined(DUK_USE_DEBUG)
9404 struct duk_fixedbuffer {
9405         duk_uint8_t *buffer;
9406         duk_size_t length;
9407         duk_size_t offset;
9408         duk_bool_t truncated;
9409 };
9410 #endif
9411
9412 /*
9413  *  Prototypes
9414  */
9415
9416 #if defined(DUK_USE_DEBUG)
9417 DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
9418 #if 0  /*unused*/
9419 DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
9420 #endif
9421 DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
9422
9423 #if defined(DUK_USE_VARIADIC_MACROS)
9424 DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
9425 #else  /* DUK_USE_VARIADIC_MACROS */
9426 /* parameter passing, not thread safe */
9427 #define DUK_DEBUG_STASH_SIZE  128
9428 #if !defined(DUK_SINGLE_FILE)
9429 DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
9430 DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash;
9431 DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
9432 DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash;
9433 #endif
9434 DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
9435 #endif  /* DUK_USE_VARIADIC_MACROS */
9436
9437 DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
9438 DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
9439 DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
9440 DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
9441 DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size);
9442 DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
9443
9444 #endif  /* DUK_USE_DEBUG */
9445
9446 #endif  /* DUK_DEBUG_H_INCLUDED */
9447 /* #include duk_error.h */
9448 #line 1 "duk_error.h"
9449 /*
9450  *  Error handling macros, assertion macro, error codes.
9451  *
9452  *  There are three types of 'errors':
9453  *
9454  *    1. Ordinary errors relative to a thread, cause a longjmp, catchable.
9455  *    2. Fatal errors relative to a heap, cause fatal handler to be called.
9456  *    3. Fatal errors without context, cause the default (not heap specific)
9457  *       fatal handler to be called.
9458  *
9459  *  Fatal errors without context are used by debug code such as assertions.
9460  *  By providing a fatal error handler for a Duktape heap, user code can
9461  *  avoid fatal errors without context in non-debug builds.
9462  */
9463
9464 #if !defined(DUK_ERROR_H_INCLUDED)
9465 #define DUK_ERROR_H_INCLUDED
9466
9467 /*
9468  *  Error codes: defined in duktape.h
9469  *
9470  *  Error codes are used as a shorthand to throw exceptions from inside
9471  *  the implementation.  The appropriate ECMAScript object is constructed
9472  *  based on the code.  ECMAScript code throws objects directly.  The error
9473  *  codes are defined in the public API header because they are also used
9474  *  by calling code.
9475  */
9476
9477 /*
9478  *  Normal error
9479  *
9480  *  Normal error is thrown with a longjmp() through the current setjmp()
9481  *  catchpoint record in the duk_heap.  The 'curr_thread' of the duk_heap
9482  *  identifies the throwing thread.
9483  *
9484  *  Error formatting is usually unnecessary.  The error macros provide a
9485  *  zero argument version (no formatting) and separate macros for small
9486  *  argument counts.  Variadic macros are not used to avoid portability
9487  *  issues and avoid the need for stash-based workarounds when they're not
9488  *  available.  Vararg calls are avoided for non-formatted error calls
9489  *  because vararg call sites are larger than normal, and there are a lot
9490  *  of call sites with no formatting.
9491  *
9492  *  Note that special formatting provided by debug macros is NOT available.
9493  *
9494  *  The _RAW variants allow the caller to specify file and line.  This makes
9495  *  it easier to write checked calls which want to use the call site of the
9496  *  checked function, not the error macro call inside the checked function.
9497  */
9498
9499 #if defined(DUK_USE_VERBOSE_ERRORS)
9500
9501 /* Because there are quite many call sites, pack error code (require at most
9502  * 8-bit) into a single argument.
9503  */
9504 #define DUK_ERROR(thr,err,msg) do { \
9505                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9506                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9507                 duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
9508         } while (0)
9509 #define DUK_ERROR_RAW(thr,file,line,err,msg) do { \
9510                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9511                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9512                 duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
9513         } while (0)
9514
9515 #define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \
9516                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9517                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9518                 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
9519         } while (0)
9520 #define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \
9521                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9522                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9523                 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
9524         } while (0)
9525
9526 #define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \
9527                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9528                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9529                 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
9530         } while (0)
9531 #define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \
9532                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9533                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9534                 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
9535         } while (0)
9536
9537 #define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \
9538                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9539                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9540                 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
9541         } while (0)
9542 #define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \
9543                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9544                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9545                 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
9546         } while (0)
9547
9548 #define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \
9549                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
9550                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9551                 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)); \
9552         } while (0)
9553 #define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \
9554                 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
9555                 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
9556                 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
9557         } while (0)
9558
9559 #else  /* DUK_USE_VERBOSE_ERRORS */
9560
9561 #define DUK_ERROR(thr,err,msg)                    duk_err_handle_error((thr), (err))
9562 #define DUK_ERROR_RAW(thr,file,line,err,msg)      duk_err_handle_error((thr), (err))
9563
9564 #define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt))
9565 #define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
9566
9567 #define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt))
9568 #define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
9569
9570 #define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt))
9571 #define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
9572
9573 #define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt))
9574 #define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
9575
9576 #endif  /* DUK_USE_VERBOSE_ERRORS */
9577
9578 /*
9579  *  Fatal error without context
9580  *
9581  *  The macro is an expression to make it compatible with DUK_ASSERT_EXPR().
9582  */
9583
9584 #define DUK_FATAL_WITHOUT_CONTEXT(msg) \
9585         duk_default_fatal_handler(NULL, (msg))
9586
9587 /*
9588  *  Error throwing helpers
9589  *
9590  *  The goal is to provide verbose and configurable error messages.  Call
9591  *  sites should be clean in source code and compile to a small footprint.
9592  *  Small footprint is also useful for performance because small cold paths
9593  *  reduce code cache pressure.  Adding macros here only makes sense if there
9594  *  are enough call sites to get concrete benefits.
9595  *
9596  *  DUK_ERROR_xxx() macros are generic and can be used anywhere.
9597  *
9598  *  DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where
9599  *  the "return DUK_RET_xxx;" shorthand is available for low memory targets.
9600  *  The DUK_DCERROR_xxx() macros always either throw or perform a
9601  *  'return DUK_RET_xxx' from the calling function.
9602  */
9603
9604 #if defined(DUK_USE_VERBOSE_ERRORS)
9605 /* Verbose errors with key/value summaries (non-paranoid) or without key/value
9606  * summaries (paranoid, for some security sensitive environments), the paranoid
9607  * vs. non-paranoid distinction affects only a few specific errors.
9608  */
9609 #if defined(DUK_USE_PARANOID_ERRORS)
9610 #define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
9611                 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
9612         } while (0)
9613 #else  /* DUK_USE_PARANOID_ERRORS */
9614 #define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
9615                 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
9616         } while (0)
9617 #endif  /* DUK_USE_PARANOID_ERRORS */
9618
9619 #define DUK_ERROR_INTERNAL(thr) do { \
9620                 duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9621         } while (0)
9622 #define DUK_DCERROR_INTERNAL(thr) do { \
9623                 DUK_ERROR_INTERNAL((thr)); \
9624                 return 0; \
9625         } while (0)
9626 #define DUK_ERROR_ALLOC_FAILED(thr) do { \
9627                 duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9628         } while (0)
9629 #define DUK_ERROR_UNSUPPORTED(thr) do { \
9630                 DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \
9631         } while (0)
9632 #define DUK_ERROR_ERROR(thr,msg) do { \
9633                 duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
9634         } while (0)
9635 #define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
9636                 duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \
9637         } while (0)
9638 #define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
9639                 duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9640         } while (0)
9641 #define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
9642                 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \
9643         } while (0)
9644 #define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
9645                 DUK_ERROR_RANGE_INVALID_ARGS((thr)); \
9646                 return 0; \
9647         } while (0)
9648 #define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
9649                 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \
9650         } while (0)
9651 #define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
9652                 DUK_ERROR_RANGE_INVALID_COUNT((thr)); \
9653                 return 0; \
9654         } while (0)
9655 #define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
9656                 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \
9657         } while (0)
9658 #define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
9659                 DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \
9660                 return 0; \
9661         } while (0)
9662 #define DUK_ERROR_RANGE(thr,msg) do { \
9663                 duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
9664         } while (0)
9665 #define DUK_ERROR_EVAL(thr,msg) do { \
9666                 DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \
9667         } while (0)
9668 #define DUK_ERROR_REFERENCE(thr,msg) do { \
9669                 DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \
9670         } while (0)
9671 #define DUK_ERROR_SYNTAX(thr,msg) do { \
9672                 DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
9673         } while (0)
9674 #define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
9675                 duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9676         } while (0)
9677 #define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
9678                 DUK_ERROR_TYPE_INVALID_ARGS((thr)); \
9679                 return 0; \
9680         } while (0)
9681 #define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
9682                 duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9683         } while (0)
9684 #define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
9685                 DUK_ERROR_TYPE_INVALID_STATE((thr)); \
9686                 return 0; \
9687         } while (0)
9688 #define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9689                 duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
9690         } while (0)
9691 #define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9692                 DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \
9693         } while (0)
9694 #define DUK_ERROR_TYPE(thr,msg) do { \
9695                 DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
9696         } while (0)
9697 #define DUK_ERROR_URI(thr,msg) do { \
9698                 DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \
9699         } while (0)
9700 #else  /* DUK_USE_VERBOSE_ERRORS */
9701 /* Non-verbose errors for low memory targets: no file, line, or message. */
9702
9703 #define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
9704                 duk_err_type((thr)); \
9705         } while (0)
9706
9707 #define DUK_ERROR_INTERNAL(thr) do { \
9708                 duk_err_error((thr)); \
9709         } while (0)
9710 #define DUK_DCERROR_INTERNAL(thr) do { \
9711                 DUK_UNREF((thr)); \
9712                 return DUK_RET_ERROR; \
9713         } while (0)
9714 #define DUK_ERROR_ALLOC_FAILED(thr) do { \
9715                 duk_err_error((thr)); \
9716         } while (0)
9717 #define DUK_ERROR_UNSUPPORTED(thr) do { \
9718                 duk_err_error((thr)); \
9719         } while (0)
9720 #define DUK_ERROR_ERROR(thr,msg) do { \
9721                 duk_err_error((thr)); \
9722         } while (0)
9723 #define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
9724                 duk_err_range((thr)); \
9725         } while (0)
9726 #define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
9727                 duk_err_range((thr)); \
9728         } while (0)
9729 #define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
9730                 duk_err_range((thr)); \
9731         } while (0)
9732 #define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
9733                 DUK_UNREF((thr)); \
9734                 return DUK_RET_RANGE_ERROR; \
9735         } while (0)
9736 #define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
9737                 duk_err_range((thr)); \
9738         } while (0)
9739 #define DUK_DCERROR_RANGE_INVALID_COUNT(thr) do { \
9740                 DUK_UNREF((thr)); \
9741                 return DUK_RET_RANGE_ERROR; \
9742         } while (0)
9743 #define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
9744                 duk_err_range((thr)); \
9745         } while (0)
9746 #define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
9747                 DUK_UNREF((thr)); \
9748                 return DUK_RET_RANGE_ERROR; \
9749         } while (0)
9750 #define DUK_ERROR_RANGE(thr,msg) do { \
9751                 duk_err_range((thr)); \
9752         } while (0)
9753 #define DUK_ERROR_EVAL(thr,msg) do { \
9754                 duk_err_eval((thr)); \
9755         } while (0)
9756 #define DUK_ERROR_REFERENCE(thr,msg) do { \
9757                 duk_err_reference((thr)); \
9758         } while (0)
9759 #define DUK_ERROR_SYNTAX(thr,msg) do { \
9760                 duk_err_syntax((thr)); \
9761         } while (0)
9762 #define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
9763                 duk_err_type((thr)); \
9764         } while (0)
9765 #define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
9766                 DUK_UNREF((thr)); \
9767                 return DUK_RET_TYPE_ERROR; \
9768         } while (0)
9769 #define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
9770                 duk_err_type((thr)); \
9771         } while (0)
9772 #define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
9773                 duk_err_type((thr)); \
9774         } while (0)
9775 #define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9776                 duk_err_type((thr)); \
9777         } while (0)
9778 #define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9779                 DUK_UNREF((thr)); \
9780                 return DUK_RET_TYPE_ERROR; \
9781         } while (0)
9782 #define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
9783                 duk_err_type((thr)); \
9784         } while (0)
9785 #define DUK_ERROR_TYPE(thr,msg) do { \
9786                 duk_err_type((thr)); \
9787         } while (0)
9788 #define DUK_ERROR_URI(thr,msg) do { \
9789                 duk_err_uri((thr)); \
9790         } while (0)
9791 #endif  /* DUK_USE_VERBOSE_ERRORS */
9792
9793 /*
9794  *  Assert macro: failure causes a fatal error.
9795  *
9796  *  NOTE: since the assert macro doesn't take a heap/context argument, there's
9797  *  no way to look up a heap/context specific fatal error handler which may have
9798  *  been given by the application.  Instead, assertion failures always use the
9799  *  internal default fatal error handler; it can be replaced via duk_config.h
9800  *  and then applies to all Duktape heaps.
9801  */
9802
9803 #if defined(DUK_USE_ASSERTIONS)
9804
9805 /* The message should be a compile time constant without formatting (less risk);
9806  * we don't care about assertion text size because they're not used in production
9807  * builds.
9808  */
9809 #define DUK_ASSERT(x)  do { \
9810         if (!(x)) { \
9811                 DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
9812                         " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
9813         } \
9814         } while (0)
9815
9816 /* Assertion compatible inside a comma expression, evaluates to void. */
9817 #define DUK_ASSERT_EXPR(x) \
9818         ((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
9819                                 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
9820
9821 #else  /* DUK_USE_ASSERTIONS */
9822
9823 #define DUK_ASSERT(x)  do { /* assertion omitted */ } while (0)
9824
9825 #define DUK_ASSERT_EXPR(x)  ((void) 0)
9826
9827 #endif  /* DUK_USE_ASSERTIONS */
9828
9829 /* this variant is used when an assert would generate a compile warning by
9830  * being always true (e.g. >= 0 comparison for an unsigned value
9831  */
9832 #define DUK_ASSERT_DISABLE(x)  do { /* assertion disabled */ } while (0)
9833
9834 /*
9835  *  Assertion helpers
9836  */
9837
9838 #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
9839 #define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h)  do { \
9840                 DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \
9841         } while (0)
9842 #define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv)  do { \
9843                 if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \
9844                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \
9845                 } \
9846         } while (0)
9847 #else
9848 #define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h)  /* no refcount check */
9849 #define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv)    /* no refcount check */
9850 #endif
9851
9852 #define DUK_ASSERT_TOP(ctx,n)  DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n))
9853
9854 #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL)
9855 #define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval)  do { \
9856                 duk_double_union duk__assert_tmp_du; \
9857                 duk__assert_tmp_du.d = (dval); \
9858                 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \
9859         } while (0)
9860 #else
9861 #define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval)  /* nop */
9862 #endif
9863
9864 #define DUK_ASSERT_VS_SPACE(thr) \
9865         DUK_ASSERT(thr->valstack_top < thr->valstack_end)
9866
9867 /*
9868  *  Helper to initialize a memory area (e.g. struct) with garbage when
9869  *  assertions enabled.
9870  */
9871
9872 #if defined(DUK_USE_ASSERTIONS)
9873 #define DUK_ASSERT_SET_GARBAGE(ptr,size) do { \
9874                 duk_memset_unsafe((void *) (ptr), 0x5a, size); \
9875         } while (0)
9876 #else
9877 #define DUK_ASSERT_SET_GARBAGE(ptr,size) do {} while (0)
9878 #endif
9879
9880 /*
9881  *  Helper for valstack space
9882  *
9883  *  Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
9884  *  required for its own use, and any child calls which are not (a) Duktape API calls
9885  *  or (b) Duktape calls which involve extending the valstack (e.g. getter call).
9886  */
9887
9888 #define DUK_VALSTACK_ASSERT_EXTRA  5  /* this is added to checks to allow for Duktape
9889                                        * API calls in addition to function's own use
9890                                        */
9891 #if defined(DUK_USE_ASSERTIONS)
9892 #define DUK_ASSERT_VALSTACK_SPACE(thr,n)   do { \
9893                 DUK_ASSERT((thr) != NULL); \
9894                 DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \
9895         } while (0)
9896 #else
9897 #define DUK_ASSERT_VALSTACK_SPACE(thr,n)   /* no valstack space check */
9898 #endif
9899
9900 /*
9901  *  Prototypes
9902  */
9903
9904 #if defined(DUK_USE_VERBOSE_ERRORS)
9905 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg));
9906 DUK_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, ...));
9907 #else  /* DUK_USE_VERBOSE_ERRORS */
9908 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code));
9909 #endif  /* DUK_USE_VERBOSE_ERRORS */
9910
9911 #if defined(DUK_USE_VERBOSE_ERRORS)
9912 DUK_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));
9913 #else
9914 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code));
9915 #endif
9916
9917 DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
9918
9919 #define DUK_AUGMENT_FLAG_NOBLAME_FILELINE  (1U << 0)  /* if set, don't blame C file/line for .fileName and .lineNumber */
9920 #define DUK_AUGMENT_FLAG_SKIP_ONE          (1U << 1)  /* if set, skip topmost activation in traceback construction */
9921
9922 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
9923 DUK_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);
9924 #endif
9925 #if defined(DUK_USE_AUGMENT_ERROR_THROW)
9926 DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
9927 #endif
9928
9929 #if defined(DUK_USE_VERBOSE_ERRORS)
9930 #if defined(DUK_USE_PARANOID_ERRORS)
9931 DUK_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));
9932 #else
9933 DUK_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));
9934 #endif
9935 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber));
9936 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber));
9937 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
9938 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx));
9939 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber));
9940 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
9941 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber));
9942 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber));
9943 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber));
9944 #else  /* DUK_VERBOSE_ERRORS */
9945 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr));
9946 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
9947 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr));
9948 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr));
9949 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
9950 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
9951 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr));
9952 #endif /* DUK_VERBOSE_ERRORS */
9953
9954 DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
9955
9956 DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg));
9957
9958 DUK_INTERNAL_DECL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val);
9959 #if defined(DUK_USE_DEBUGGER_SUPPORT)
9960 DUK_INTERNAL_DECL void duk_err_check_debugger_integration(duk_hthread *thr);
9961 #endif
9962
9963 DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
9964
9965 #endif  /* DUK_ERROR_H_INCLUDED */
9966 /* #include duk_unicode.h */
9967 #line 1 "duk_unicode.h"
9968 /*
9969  *  Unicode helpers
9970  */
9971
9972 #if !defined(DUK_UNICODE_H_INCLUDED)
9973 #define DUK_UNICODE_H_INCLUDED
9974
9975 /*
9976  *  UTF-8 / XUTF-8 / CESU-8 constants
9977  */
9978
9979 #define DUK_UNICODE_MAX_XUTF8_LENGTH      7   /* up to 36 bit codepoints */
9980 #define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH  3   /* all codepoints up to U+FFFF */
9981 #define DUK_UNICODE_MAX_CESU8_LENGTH      6   /* all codepoints up to U+10FFFF */
9982 #define DUK_UNICODE_MAX_CESU8_BMP_LENGTH  3   /* all codepoints up to U+FFFF */
9983
9984 /*
9985  *  Useful Unicode codepoints
9986  *
9987  *  Integer constants must be signed to avoid unexpected coercions
9988  *  in comparisons.
9989  */
9990
9991 #define DUK_UNICODE_CP_ZWNJ                   0x200cL  /* zero-width non-joiner */
9992 #define DUK_UNICODE_CP_ZWJ                    0x200dL  /* zero-width joiner */
9993 #define DUK_UNICODE_CP_REPLACEMENT_CHARACTER  0xfffdL  /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */
9994
9995 /*
9996  *  ASCII character constants
9997  *
9998  *  C character literals like 'x' have a platform specific value and do
9999  *  not match ASCII (UTF-8) values on e.g. EBCDIC platforms.  So, use
10000  *  these (admittedly awkward) constants instead.  These constants must
10001  *  also have signed values to avoid unexpected coercions in comparisons.
10002  *
10003  *  http://en.wikipedia.org/wiki/ASCII
10004  */
10005
10006 #define DUK_ASC_NUL              0x00
10007 #define DUK_ASC_SOH              0x01
10008 #define DUK_ASC_STX              0x02
10009 #define DUK_ASC_ETX              0x03
10010 #define DUK_ASC_EOT              0x04
10011 #define DUK_ASC_ENQ              0x05
10012 #define DUK_ASC_ACK              0x06
10013 #define DUK_ASC_BEL              0x07
10014 #define DUK_ASC_BS               0x08
10015 #define DUK_ASC_HT               0x09
10016 #define DUK_ASC_LF               0x0a
10017 #define DUK_ASC_VT               0x0b
10018 #define DUK_ASC_FF               0x0c
10019 #define DUK_ASC_CR               0x0d
10020 #define DUK_ASC_SO               0x0e
10021 #define DUK_ASC_SI               0x0f
10022 #define DUK_ASC_DLE              0x10
10023 #define DUK_ASC_DC1              0x11
10024 #define DUK_ASC_DC2              0x12
10025 #define DUK_ASC_DC3              0x13
10026 #define DUK_ASC_DC4              0x14
10027 #define DUK_ASC_NAK              0x15
10028 #define DUK_ASC_SYN              0x16
10029 #define DUK_ASC_ETB              0x17
10030 #define DUK_ASC_CAN              0x18
10031 #define DUK_ASC_EM               0x19
10032 #define DUK_ASC_SUB              0x1a
10033 #define DUK_ASC_ESC              0x1b
10034 #define DUK_ASC_FS               0x1c
10035 #define DUK_ASC_GS               0x1d
10036 #define DUK_ASC_RS               0x1e
10037 #define DUK_ASC_US               0x1f
10038 #define DUK_ASC_SPACE            0x20
10039 #define DUK_ASC_EXCLAMATION      0x21
10040 #define DUK_ASC_DOUBLEQUOTE      0x22
10041 #define DUK_ASC_HASH             0x23
10042 #define DUK_ASC_DOLLAR           0x24
10043 #define DUK_ASC_PERCENT          0x25
10044 #define DUK_ASC_AMP              0x26
10045 #define DUK_ASC_SINGLEQUOTE      0x27
10046 #define DUK_ASC_LPAREN           0x28
10047 #define DUK_ASC_RPAREN           0x29
10048 #define DUK_ASC_STAR             0x2a
10049 #define DUK_ASC_PLUS             0x2b
10050 #define DUK_ASC_COMMA            0x2c
10051 #define DUK_ASC_MINUS            0x2d
10052 #define DUK_ASC_PERIOD           0x2e
10053 #define DUK_ASC_SLASH            0x2f
10054 #define DUK_ASC_0                0x30
10055 #define DUK_ASC_1                0x31
10056 #define DUK_ASC_2                0x32
10057 #define DUK_ASC_3                0x33
10058 #define DUK_ASC_4                0x34
10059 #define DUK_ASC_5                0x35
10060 #define DUK_ASC_6                0x36
10061 #define DUK_ASC_7                0x37
10062 #define DUK_ASC_8                0x38
10063 #define DUK_ASC_9                0x39
10064 #define DUK_ASC_COLON            0x3a
10065 #define DUK_ASC_SEMICOLON        0x3b
10066 #define DUK_ASC_LANGLE           0x3c
10067 #define DUK_ASC_EQUALS           0x3d
10068 #define DUK_ASC_RANGLE           0x3e
10069 #define DUK_ASC_QUESTION         0x3f
10070 #define DUK_ASC_ATSIGN           0x40
10071 #define DUK_ASC_UC_A             0x41
10072 #define DUK_ASC_UC_B             0x42
10073 #define DUK_ASC_UC_C             0x43
10074 #define DUK_ASC_UC_D             0x44
10075 #define DUK_ASC_UC_E             0x45
10076 #define DUK_ASC_UC_F             0x46
10077 #define DUK_ASC_UC_G             0x47
10078 #define DUK_ASC_UC_H             0x48
10079 #define DUK_ASC_UC_I             0x49
10080 #define DUK_ASC_UC_J             0x4a
10081 #define DUK_ASC_UC_K             0x4b
10082 #define DUK_ASC_UC_L             0x4c
10083 #define DUK_ASC_UC_M             0x4d
10084 #define DUK_ASC_UC_N             0x4e
10085 #define DUK_ASC_UC_O             0x4f
10086 #define DUK_ASC_UC_P             0x50
10087 #define DUK_ASC_UC_Q             0x51
10088 #define DUK_ASC_UC_R             0x52
10089 #define DUK_ASC_UC_S             0x53
10090 #define DUK_ASC_UC_T             0x54
10091 #define DUK_ASC_UC_U             0x55
10092 #define DUK_ASC_UC_V             0x56
10093 #define DUK_ASC_UC_W             0x57
10094 #define DUK_ASC_UC_X             0x58
10095 #define DUK_ASC_UC_Y             0x59
10096 #define DUK_ASC_UC_Z             0x5a
10097 #define DUK_ASC_LBRACKET         0x5b
10098 #define DUK_ASC_BACKSLASH        0x5c
10099 #define DUK_ASC_RBRACKET         0x5d
10100 #define DUK_ASC_CARET            0x5e
10101 #define DUK_ASC_UNDERSCORE       0x5f
10102 #define DUK_ASC_GRAVE            0x60
10103 #define DUK_ASC_LC_A             0x61
10104 #define DUK_ASC_LC_B             0x62
10105 #define DUK_ASC_LC_C             0x63
10106 #define DUK_ASC_LC_D             0x64
10107 #define DUK_ASC_LC_E             0x65
10108 #define DUK_ASC_LC_F             0x66
10109 #define DUK_ASC_LC_G             0x67
10110 #define DUK_ASC_LC_H             0x68
10111 #define DUK_ASC_LC_I             0x69
10112 #define DUK_ASC_LC_J             0x6a
10113 #define DUK_ASC_LC_K             0x6b
10114 #define DUK_ASC_LC_L             0x6c
10115 #define DUK_ASC_LC_M             0x6d
10116 #define DUK_ASC_LC_N             0x6e
10117 #define DUK_ASC_LC_O             0x6f
10118 #define DUK_ASC_LC_P             0x70
10119 #define DUK_ASC_LC_Q             0x71
10120 #define DUK_ASC_LC_R             0x72
10121 #define DUK_ASC_LC_S             0x73
10122 #define DUK_ASC_LC_T             0x74
10123 #define DUK_ASC_LC_U             0x75
10124 #define DUK_ASC_LC_V             0x76
10125 #define DUK_ASC_LC_W             0x77
10126 #define DUK_ASC_LC_X             0x78
10127 #define DUK_ASC_LC_Y             0x79
10128 #define DUK_ASC_LC_Z             0x7a
10129 #define DUK_ASC_LCURLY           0x7b
10130 #define DUK_ASC_PIPE             0x7c
10131 #define DUK_ASC_RCURLY           0x7d
10132 #define DUK_ASC_TILDE            0x7e
10133 #define DUK_ASC_DEL              0x7f
10134
10135 /*
10136  *  Miscellaneous
10137  */
10138
10139 /* Uppercase A is 0x41, lowercase a is 0x61; OR 0x20 to convert uppercase
10140  * to lowercase.
10141  */
10142 #define DUK_LOWERCASE_CHAR_ASCII(x)  ((x) | 0x20)
10143
10144 /*
10145  *  Unicode tables
10146  */
10147
10148 #if defined(DUK_USE_SOURCE_NONBMP)
10149 /*
10150  *  Automatically generated by extract_chars.py, do not edit!
10151  */
10152
10153 extern const duk_uint8_t duk_unicode_ids_noa[1063];
10154 #else
10155 /*
10156  *  Automatically generated by extract_chars.py, do not edit!
10157  */
10158
10159 extern const duk_uint8_t duk_unicode_ids_noabmp[626];
10160 #endif
10161
10162 #if defined(DUK_USE_SOURCE_NONBMP)
10163 /*
10164  *  Automatically generated by extract_chars.py, do not edit!
10165  */
10166
10167 extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
10168 #else
10169 /*
10170  *  Automatically generated by extract_chars.py, do not edit!
10171  */
10172
10173 extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
10174 #endif
10175
10176 #if defined(DUK_USE_SOURCE_NONBMP)
10177 /*
10178  *  Automatically generated by extract_chars.py, do not edit!
10179  */
10180
10181 extern const duk_uint8_t duk_unicode_idp_m_ids_noa[549];
10182 #else
10183 /*
10184  *  Automatically generated by extract_chars.py, do not edit!
10185  */
10186
10187 extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358];
10188 #endif
10189
10190 /*
10191  *  Automatically generated by extract_caseconv.py, do not edit!
10192  */
10193
10194 extern const duk_uint8_t duk_unicode_caseconv_uc[1386];
10195 extern const duk_uint8_t duk_unicode_caseconv_lc[680];
10196
10197 #if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
10198 /*
10199  *  Automatically generated by extract_caseconv.py, do not edit!
10200  */
10201
10202 extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
10203 #endif
10204
10205 #if defined(DUK_USE_REGEXP_CANON_BITMAP)
10206 /*
10207  *  Automatically generated by extract_caseconv.py, do not edit!
10208  */
10209
10210 #define DUK_CANON_BITMAP_BLKSIZE                                      32
10211 #define DUK_CANON_BITMAP_BLKSHIFT                                     5
10212 #define DUK_CANON_BITMAP_BLKMASK                                      31
10213 extern const duk_uint8_t duk_unicode_re_canon_bitmap[256];
10214 #endif
10215
10216 /*
10217  *  Extern
10218  */
10219
10220 /* duk_unicode_support.c */
10221 #if !defined(DUK_SINGLE_FILE)
10222 DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7];
10223 DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2];
10224 DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22];
10225 DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8];
10226 DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4];
10227 DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24];
10228 DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10];
10229 DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128];
10230 #endif  /* !DUK_SINGLE_FILE */
10231
10232 /*
10233  *  Prototypes
10234  */
10235
10236 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp);
10237 #if defined(DUK_USE_ASSERTIONS)
10238 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp);
10239 #endif
10240 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out);
10241 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out);
10242 DUK_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);
10243 DUK_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);
10244 DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen);
10245 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp);
10246 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp);
10247 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp);
10248 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
10249 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
10250 DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase);
10251 #if defined(DUK_USE_REGEXP_SUPPORT)
10252 DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
10253 DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
10254 #endif
10255
10256 #endif  /* DUK_UNICODE_H_INCLUDED */
10257 /* #include duk_json.h */
10258 #line 1 "duk_json.h"
10259 /*
10260  *  Defines for JSON, especially duk_bi_json.c.
10261  */
10262
10263 #if !defined(DUK_JSON_H_INCLUDED)
10264 #define DUK_JSON_H_INCLUDED
10265
10266 /* Encoding/decoding flags */
10267 #define DUK_JSON_FLAG_ASCII_ONLY              (1U << 0)  /* escape any non-ASCII characters */
10268 #define DUK_JSON_FLAG_AVOID_KEY_QUOTES        (1U << 1)  /* avoid key quotes when key is an ASCII Identifier */
10269 #define DUK_JSON_FLAG_EXT_CUSTOM              (1U << 2)  /* extended types: custom encoding */
10270 #define DUK_JSON_FLAG_EXT_COMPATIBLE          (1U << 3)  /* extended types: compatible encoding */
10271
10272 /* How much stack to require on entry to object/array encode */
10273 #define DUK_JSON_ENC_REQSTACK                 32
10274
10275 /* How much stack to require on entry to object/array decode */
10276 #define DUK_JSON_DEC_REQSTACK                 32
10277
10278 /* How large a loop detection stack to use */
10279 #define DUK_JSON_ENC_LOOPARRAY                64
10280
10281 /* Encoding state.  Heap object references are all borrowed. */
10282 typedef struct {
10283         duk_hthread *thr;
10284         duk_bufwriter_ctx bw;        /* output bufwriter */
10285         duk_hobject *h_replacer;     /* replacer function */
10286         duk_hstring *h_gap;          /* gap (if empty string, NULL) */
10287         duk_idx_t idx_proplist;      /* explicit PropertyList */
10288         duk_idx_t idx_loop;          /* valstack index of loop detection object */
10289         duk_small_uint_t flags;
10290         duk_small_uint_t flag_ascii_only;
10291         duk_small_uint_t flag_avoid_key_quotes;
10292 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
10293         duk_small_uint_t flag_ext_custom;
10294         duk_small_uint_t flag_ext_compatible;
10295         duk_small_uint_t flag_ext_custom_or_compatible;
10296 #endif
10297         duk_uint_t recursion_depth;
10298         duk_uint_t recursion_limit;
10299         duk_uint_t mask_for_undefined;      /* type bit mask: types which certainly produce 'undefined' */
10300 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
10301         duk_small_uint_t stridx_custom_undefined;
10302         duk_small_uint_t stridx_custom_nan;
10303         duk_small_uint_t stridx_custom_neginf;
10304         duk_small_uint_t stridx_custom_posinf;
10305         duk_small_uint_t stridx_custom_function;
10306 #endif
10307         duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY];  /* indexed by recursion_depth */
10308 } duk_json_enc_ctx;
10309
10310 typedef struct {
10311         duk_hthread *thr;
10312         const duk_uint8_t *p;
10313         const duk_uint8_t *p_start;
10314         const duk_uint8_t *p_end;
10315         duk_idx_t idx_reviver;
10316         duk_small_uint_t flags;
10317 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
10318         duk_small_uint_t flag_ext_custom;
10319         duk_small_uint_t flag_ext_compatible;
10320         duk_small_uint_t flag_ext_custom_or_compatible;
10321 #endif
10322         duk_int_t recursion_depth;
10323         duk_int_t recursion_limit;
10324 } duk_json_dec_ctx;
10325
10326 #endif  /* DUK_JSON_H_INCLUDED */
10327 /* #include duk_js.h */
10328 #line 1 "duk_js.h"
10329 /*
10330  *  ECMAScript execution, support primitives.
10331  */
10332
10333 #if !defined(DUK_JS_H_INCLUDED)
10334 #define DUK_JS_H_INCLUDED
10335
10336 /* Flags for call handling.  Lowest flags must match bytecode DUK_BC_CALL_FLAG_xxx 1:1. */
10337 #define DUK_CALL_FLAG_TAILCALL                 (1U << 0)  /* setup for a tail call */
10338 #define DUK_CALL_FLAG_CONSTRUCT                (1U << 1)  /* constructor call (i.e. called as 'new Foo()') */
10339 #define DUK_CALL_FLAG_CALLED_AS_EVAL           (1U << 2)  /* call was made using the identifier 'eval' */
10340 #define DUK_CALL_FLAG_ALLOW_ECMATOECMA         (1U << 3)  /* ecma-to-ecma call with executor reuse is possible */
10341 #define DUK_CALL_FLAG_DIRECT_EVAL              (1U << 4)  /* call is a direct eval call */
10342 #define DUK_CALL_FLAG_CONSTRUCT_PROXY          (1U << 5)  /* handled via 'construct' proxy trap, check return value invariant(s) */
10343 #define DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED (1U << 6)  /* prototype of 'default instance' updated, temporary flag in call handling */
10344
10345 /* Flags for duk_js_equals_helper(). */
10346 #define DUK_EQUALS_FLAG_SAMEVALUE            (1U << 0)  /* use SameValue instead of non-strict equality */
10347 #define DUK_EQUALS_FLAG_STRICT               (1U << 1)  /* use strict equality instead of non-strict equality */
10348
10349 /* Flags for duk_js_compare_helper(). */
10350 #define DUK_COMPARE_FLAG_NEGATE              (1U << 0)  /* negate result */
10351 #define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST     (1U << 1)  /* eval left argument first */
10352
10353 /* conversions, coercions, comparison, etc */
10354 DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
10355 DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv);
10356 DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x);
10357 DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
10358 DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
10359 DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
10360 DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
10361 DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen);
10362 #if !defined(DUK_USE_HSTRING_ARRIDX)
10363 DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h);
10364 DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h);
10365 #endif
10366 DUK_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);
10367 DUK_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);
10368 DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
10369 #if 0  /* unused */
10370 DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
10371 #endif
10372 DUK_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);
10373 DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
10374 #if defined(DUK_USE_SYMBOL_BUILTIN)
10375 DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
10376 #endif
10377 DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
10378 DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x);
10379
10380 /* arithmetic */
10381 DUK_INTERNAL_DECL double duk_js_arith_pow(double x, double y);
10382 DUK_INTERNAL_DECL double duk_js_arith_mod(double x, double y);
10383
10384 #define duk_js_equals(thr,tv_x,tv_y) \
10385         duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
10386 #define duk_js_strict_equals(tv_x,tv_y) \
10387         duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)
10388 #define duk_js_samevalue(tv_x,tv_y) \
10389         duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)
10390
10391 /* E5 Sections 11.8.1, 11.8.5; x < y */
10392 #define duk_js_lessthan(thr,tv_x,tv_y) \
10393         duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
10394
10395 /* E5 Sections 11.8.2, 11.8.5; x > y  -->  y < x */
10396 #define duk_js_greaterthan(thr,tv_x,tv_y) \
10397         duk_js_compare_helper((thr), (tv_y), (tv_x), 0)
10398
10399 /* E5 Sections 11.8.3, 11.8.5; x <= y  -->  not (x > y)  -->  not (y < x) */
10400 #define duk_js_lessthanorequal(thr,tv_x,tv_y) \
10401         duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)
10402
10403 /* E5 Sections 11.8.4, 11.8.5; x >= y  -->  not (x < y) */
10404 #define duk_js_greaterthanorequal(thr,tv_x,tv_y) \
10405         duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
10406
10407 /* identifiers and environment handling */
10408 #if 0  /*unused*/
10409 DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
10410 #endif
10411 DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag);
10412 DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag);
10413 DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict);
10414 DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict);
10415 #if 0  /*unused*/
10416 DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
10417 #endif
10418 DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
10419 DUK_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);
10420 DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
10421 DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env);
10422 DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t bottom_byteoff);
10423 DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr,
10424                                            duk_hcompfunc *fun_temp,
10425                                            duk_hobject *outer_var_env,
10426                                            duk_hobject *outer_lex_env,
10427                                            duk_bool_t add_auto_proto);
10428
10429 /* call handling */
10430 DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t idx_func, duk_small_uint_t call_flags);
10431 DUK_INTERNAL_DECL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags);
10432 DUK_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);
10433 DUK_INTERNAL_DECL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant);
10434 #if defined(DUK_USE_VERBOSE_ERRORS)
10435 DUK_INTERNAL_DECL void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key);
10436 #endif
10437
10438 /* bytecode execution */
10439 DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
10440
10441 #endif  /* DUK_JS_H_INCLUDED */
10442 /* #include duk_numconv.h */
10443 #line 1 "duk_numconv.h"
10444 /*
10445  *  Number-to-string conversion.  The semantics of these is very tightly
10446  *  bound with the ECMAScript semantics required for call sites.
10447  */
10448
10449 #if !defined(DUK_NUMCONV_H_INCLUDED)
10450 #define DUK_NUMCONV_H_INCLUDED
10451
10452 /* Output a specified number of digits instead of using the shortest
10453  * form.  Used for toPrecision() and toFixed().
10454  */
10455 #define DUK_N2S_FLAG_FIXED_FORMAT         (1U << 0)
10456
10457 /* Force exponential format.  Used for toExponential(). */
10458 #define DUK_N2S_FLAG_FORCE_EXP            (1U << 1)
10459
10460 /* If number would need zero padding (for whole number part), use
10461  * exponential format instead.  E.g. if input number is 12300, 3
10462  * digits are generated ("123"), output "1.23e+4" instead of "12300".
10463  * Used for toPrecision().
10464  */
10465 #define DUK_N2S_FLAG_NO_ZERO_PAD          (1U << 2)
10466
10467 /* Digit count indicates number of fractions (i.e. an absolute
10468  * digit index instead of a relative one).  Used together with
10469  * DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
10470  */
10471 #define DUK_N2S_FLAG_FRACTION_DIGITS      (1U << 3)
10472
10473 /*
10474  *  String-to-number conversion
10475  */
10476
10477 /* Maximum exponent value when parsing numbers.  This is not strictly
10478  * compliant as there should be no upper limit, but as we parse the
10479  * exponent without a bigint, impose some limit.  The limit should be
10480  * small enough that multiplying it (or limit-1 to be precise) won't
10481  * overflow signed 32-bit integer range.  Exponent is only parsed with
10482  * radix 10, but with maximum radix (36) a safe limit is:
10483  * (10000000*36).toString(16) -> '15752a00'
10484  */
10485 #define DUK_S2N_MAX_EXPONENT              10000000L
10486
10487 /* Trim white space (= allow leading and trailing whitespace) */
10488 #define DUK_S2N_FLAG_TRIM_WHITE           (1U << 0)
10489
10490 /* Allow exponent */
10491 #define DUK_S2N_FLAG_ALLOW_EXP            (1U << 1)
10492
10493 /* Allow trailing garbage (e.g. treat "123foo" as "123) */
10494 #define DUK_S2N_FLAG_ALLOW_GARBAGE        (1U << 2)
10495
10496 /* Allow leading plus sign */
10497 #define DUK_S2N_FLAG_ALLOW_PLUS           (1U << 3)
10498
10499 /* Allow leading minus sign */
10500 #define DUK_S2N_FLAG_ALLOW_MINUS          (1U << 4)
10501
10502 /* Allow 'Infinity' */
10503 #define DUK_S2N_FLAG_ALLOW_INF            (1U << 5)
10504
10505 /* Allow fraction part */
10506 #define DUK_S2N_FLAG_ALLOW_FRAC           (1U << 6)
10507
10508 /* Allow naked fraction (e.g. ".123") */
10509 #define DUK_S2N_FLAG_ALLOW_NAKED_FRAC     (1U << 7)
10510
10511 /* Allow empty fraction (e.g. "123.") */
10512 #define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC     (1U << 8)
10513
10514 /* Allow empty string to be interpreted as 0 */
10515 #define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO  (1U << 9)
10516
10517 /* Allow leading zeroes (e.g. "0123" -> "123") */
10518 #define DUK_S2N_FLAG_ALLOW_LEADING_ZERO   (1U << 10)
10519
10520 /* Allow automatic detection of hex base ("0x" or "0X" prefix),
10521  * overrides radix argument and forces integer mode.
10522  */
10523 #define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT   (1U << 11)
10524
10525 /* Allow automatic detection of legacy octal base ("0n"),
10526  * overrides radix argument and forces integer mode.
10527  */
10528 #define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT   (1U << 12)
10529
10530 /* Allow automatic detection of ES2015 octal base ("0o123"),
10531  * overrides radix argument and forces integer mode.
10532  */
10533 #define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT   (1U << 13)
10534
10535 /* Allow automatic detection of ES2015 binary base ("0b10001"),
10536  * overrides radix argument and forces integer mode.
10537  */
10538 #define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT   (1U << 14)
10539
10540 /*
10541  *  Prototypes
10542  */
10543
10544 DUK_INTERNAL_DECL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
10545 DUK_INTERNAL_DECL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags);
10546
10547 #endif  /* DUK_NUMCONV_H_INCLUDED */
10548 /* #include duk_bi_protos.h */
10549 #line 1 "duk_bi_protos.h"
10550 /*
10551  *  Prototypes for built-in functions not automatically covered by the
10552  *  header declarations emitted by genbuiltins.py.
10553  */
10554
10555 #if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED)
10556 #define DUK_BUILTIN_PROTOS_H_INCLUDED
10557
10558 /* Buffer size needed for ISO 8601 formatting.
10559  * Accurate value is 32 + 1 for NUL termination:
10560  *   >>> len('+123456-01-23T12:34:56.123+12:34')
10561  *   32
10562  * Include additional space to be safe.
10563  */
10564 #define  DUK_BI_DATE_ISO8601_BUFSIZE  40
10565
10566 /* Helpers exposed for internal use */
10567 DUK_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);
10568 DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
10569 DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
10570 DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
10571 DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
10572 DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
10573 /* Built-in providers */
10574 #if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
10575 DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(void);
10576 #endif
10577 #if defined(DUK_USE_DATE_NOW_TIME)
10578 DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(void);
10579 #endif
10580 #if defined(DUK_USE_DATE_NOW_WINDOWS)
10581 DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(void);
10582 #endif
10583 #if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
10584 DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows_subms(void);
10585 #endif
10586 #if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
10587 DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
10588 #endif
10589 #if defined(DUK_USE_DATE_TZO_WINDOWS)
10590 DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
10591 #endif
10592 #if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
10593 DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d);
10594 #endif
10595 #if defined(DUK_USE_DATE_PRS_STRPTIME)
10596 DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str);
10597 #endif
10598 #if defined(DUK_USE_DATE_PRS_GETDATE)
10599 DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str);
10600 #endif
10601 #if defined(DUK_USE_DATE_FMT_STRFTIME)
10602 DUK_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);
10603 #endif
10604
10605 #if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
10606 DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void);
10607 #endif
10608 #if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
10609 DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void);
10610 #endif
10611
10612 DUK_INTERNAL_DECL
10613 void duk_bi_json_parse_helper(duk_hthread *thr,
10614                               duk_idx_t idx_value,
10615                               duk_idx_t idx_reviver,
10616                               duk_small_uint_t flags);
10617 DUK_INTERNAL_DECL
10618 void duk_bi_json_stringify_helper(duk_hthread *thr,
10619                                   duk_idx_t idx_value,
10620                                   duk_idx_t idx_replacer,
10621                                   duk_idx_t idx_space,
10622                                   duk_small_uint_t flags);
10623
10624 DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr);
10625
10626 #if defined(DUK_USE_ES6_PROXY)
10627 DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags);
10628 #endif
10629
10630 #endif  /* DUK_BUILTIN_PROTOS_H_INCLUDED */
10631 /* #include duk_selftest.h */
10632 #line 1 "duk_selftest.h"
10633 /*
10634  *  Selftest code
10635  */
10636
10637 #if !defined(DUK_SELFTEST_H_INCLUDED)
10638 #define DUK_SELFTEST_H_INCLUDED
10639
10640 #if defined(DUK_USE_SELF_TESTS)
10641 DUK_INTERNAL_DECL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
10642                                                     duk_realloc_function realloc_func,
10643                                                     duk_free_function free_func,
10644                                                     void *udata);
10645 #endif
10646
10647 #endif  /* DUK_SELFTEST_H_INCLUDED */
10648 #line 82 "duk_internal.h"
10649
10650 #endif  /* DUK_INTERNAL_H_INCLUDED */
10651 #line 10 "duk_replacements.c"
10652
10653 #if defined(DUK_USE_COMPUTED_NAN)
10654 DUK_INTERNAL double duk_computed_nan;
10655 #endif
10656
10657 #if defined(DUK_USE_COMPUTED_INFINITY)
10658 DUK_INTERNAL double duk_computed_infinity;
10659 #endif
10660
10661 #if defined(DUK_USE_REPL_FPCLASSIFY)
10662 DUK_INTERNAL int duk_repl_fpclassify(double x) {
10663         duk_double_union u;
10664         duk_uint_fast16_t expt;
10665         duk_small_int_t mzero;
10666
10667         u.d = x;
10668         expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL);
10669         if (expt > 0x0000UL && expt < 0x7ff0UL) {
10670                 /* expt values [0x001,0x7fe] = normal */
10671                 return DUK_FP_NORMAL;
10672         }
10673
10674         mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0);
10675         if (expt == 0x0000UL) {
10676                 /* expt 0x000 is zero/subnormal */
10677                 if (mzero) {
10678                         return DUK_FP_ZERO;
10679                 } else {
10680                         return DUK_FP_SUBNORMAL;
10681                 }
10682         } else {
10683                 /* expt 0xfff is infinite/nan */
10684                 if (mzero) {
10685                         return DUK_FP_INFINITE;
10686                 } else {
10687                         return DUK_FP_NAN;
10688                 }
10689         }
10690 }
10691 #endif
10692
10693 #if defined(DUK_USE_REPL_SIGNBIT)
10694 DUK_INTERNAL int duk_repl_signbit(double x) {
10695         duk_double_union u;
10696         u.d = x;
10697         return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL);
10698 }
10699 #endif
10700
10701 #if defined(DUK_USE_REPL_ISFINITE)
10702 DUK_INTERNAL int duk_repl_isfinite(double x) {
10703         int c = DUK_FPCLASSIFY(x);
10704         if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
10705                 return 0;
10706         } else {
10707                 return 1;
10708         }
10709 }
10710 #endif
10711
10712 #if defined(DUK_USE_REPL_ISNAN)
10713 DUK_INTERNAL int duk_repl_isnan(double x) {
10714         int c = DUK_FPCLASSIFY(x);
10715         return (c == DUK_FP_NAN);
10716 }
10717 #endif
10718
10719 #if defined(DUK_USE_REPL_ISINF)
10720 DUK_INTERNAL int duk_repl_isinf(double x) {
10721         int c = DUK_FPCLASSIFY(x);
10722         return (c == DUK_FP_INFINITE);
10723 }
10724 #endif
10725 #line 1 "duk_debug_macros.c"
10726 /*
10727  *  Debugging macro calls.
10728  */
10729
10730 /* #include duk_internal.h -> already included */
10731
10732 #if defined(DUK_USE_DEBUG)
10733
10734 /*
10735  *  Debugging enabled
10736  */
10737
10738 #include <stdio.h>
10739 #include <stdlib.h>
10740 #include <stdarg.h>
10741
10742 #if !defined(DUK_USE_DEBUG_WRITE)
10743 #error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined
10744 #endif
10745
10746 #define DUK__DEBUG_BUFSIZE  DUK_USE_DEBUG_BUFSIZE
10747
10748 #if defined(DUK_USE_VARIADIC_MACROS)
10749
10750 DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
10751         va_list ap;
10752         long arg_level;
10753         const char *arg_file;
10754         long arg_line;
10755         const char *arg_func;
10756         const char *arg_msg;
10757         char buf[DUK__DEBUG_BUFSIZE];
10758
10759         va_start(ap, fmt);
10760
10761         duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
10762         duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
10763
10764         arg_level = (long) level;
10765         arg_file = (const char *) file;
10766         arg_line = (long) line;
10767         arg_func = (const char *) func;
10768         arg_msg = (const char *) buf;
10769         DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
10770
10771         va_end(ap);
10772 }
10773
10774 #else  /* DUK_USE_VARIADIC_MACROS */
10775
10776 DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
10777 DUK_INTERNAL duk_int_t duk_debug_line_stash;
10778 DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
10779 DUK_INTERNAL duk_int_t duk_debug_level_stash;
10780
10781 DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
10782         va_list ap;
10783         long arg_level;
10784         const char *arg_file;
10785         long arg_line;
10786         const char *arg_func;
10787         const char *arg_msg;
10788         char buf[DUK__DEBUG_BUFSIZE];
10789
10790         va_start(ap, fmt);
10791
10792         duk_memzero((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
10793         duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
10794
10795         arg_level = (long) duk_debug_level_stash;
10796         arg_file = (const char *) duk_debug_file_stash;
10797         arg_line = (long) duk_debug_line_stash;
10798         arg_func = (const char *) duk_debug_func_stash;
10799         arg_msg = (const char *) buf;
10800         DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
10801
10802         va_end(ap);
10803 }
10804
10805 #endif  /* DUK_USE_VARIADIC_MACROS */
10806
10807 #else  /* DUK_USE_DEBUG */
10808
10809 /*
10810  *  Debugging disabled
10811  */
10812
10813 #endif  /* DUK_USE_DEBUG */
10814
10815 /* automatic undefs */
10816 #undef DUK__DEBUG_BUFSIZE
10817 #line 1 "duk_builtins.c"
10818 /*
10819  *  Automatically generated by genbuiltins.py, do not edit!
10820  */
10821
10822 /* #include duk_internal.h -> already included */
10823
10824 #if defined(DUK_USE_ASSERTIONS)
10825 #define DUK__REFCINIT(refc) 0 /*h_assert_refcount*/, (refc) /*actual*/
10826 #else
10827 #define DUK__REFCINIT(refc) (refc) /*actual*/
10828 #endif
10829
10830 #if defined(DUK_USE_ROM_STRINGS)
10831 #error ROM support not enabled, rerun configure.py with --rom-support
10832 #else  /* DUK_USE_ROM_STRINGS */
10833 DUK_INTERNAL const duk_uint8_t duk_strings_data[967] = {
10834 79,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103,
10835 35,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31,
10836 129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132,
10837 140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224,
10838 193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32,
10839 196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8,
10840 196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11,
10841 229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10,
10842 183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32,
10843 184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64,
10844 178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18,
10845 32,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156,
10846 113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115,
10847 119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137,
10848 101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75,
10849 226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64,
10850 52,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133,
10851 67,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2,
10852 249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190,
10853 186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12,
10854 32,45,100,137,64,247,175,9,19,155,41,198,130,155,134,69,146,100,227,226,
10855 231,146,51,192,204,73,140,224,145,221,102,241,68,196,169,248,30,75,12,11,
10856 151,242,233,187,143,138,24,137,162,164,255,253,63,3,201,97,129,114,254,92,
10857 112,75,136,108,166,6,136,159,255,167,224,121,44,48,46,95,203,166,238,74,
10858 113,67,77,201,128,223,255,223,224,121,44,48,46,95,203,145,46,9,205,16,39,
10859 201,62,36,0,192,21,147,255,238,145,39,199,197,211,116,240,242,113,197,78,
10860 214,211,226,233,187,107,105,19,119,37,56,161,166,52,221,212,201,205,36,240,
10861 242,16,96,152,12,178,52,211,56,228,73,150,83,0,148,39,137,75,67,73,198,209,
10862 129,36,85,185,201,196,2,32,193,48,17,160,97,16,84,44,156,104,24,67,189,200,
10863 108,201,19,238,114,96,137,137,50,238,113,164,188,211,185,192,226,100,19,
10864 134,68,110,112,174,139,0,185,31,115,149,4,88,7,159,115,146,117,34,34,35,
10865 115,143,22,146,208,210,19,115,140,3,207,185,202,130,36,109,85,185,194,161,
10866 160,90,50,72,155,115,149,2,232,67,137,204,122,22,66,161,175,164,210,72,199,
10867 130,137,1,50,32,145,143,38,120,186,195,35,106,51,146,230,8,36,77,109,65,38,
10868 226,72,159,191,189,181,70,140,133,222,249,212,227,66,125,245,187,251,219,
10869 77,3,119,190,117,56,208,159,125,110,254,246,210,26,93,239,157,78,52,39,223,
10870 93,191,189,180,212,52,187,223,58,156,104,79,190,187,127,123,104,180,104,
10871 183,190,117,56,208,159,125,102,254,209,104,209,124,234,113,161,62,250,80,
10872 196,128,81,4,9,16,162,4,196,116,9,205,154,27,66,32,100,13,12,98,68,227,33,
10873 65,69,204,195,34,201,50,8,110,33,23,34,28,168,104,22,188,12,174,138,11,70,
10874 138,104,115,68,130,137,13,82,27,41,129,162,35,138,54,146,198,137,39,72,180,
10875 210,178,38,35,146,103,68,139,51,197,214,28,227,131,79,15,35,138,58,130,37,
10876 19,155,41,146,174,64,203,99,161,100,37,145,51,148,75,4,164,66,54,140,49,46,
10877 247,70,103,37,230,70,142,70,67,30,232,204,178,163,201,18,54,139,89,39,26,
10878 16,165,2,228,69,33,143,89,24,70,206,73,67,102,72,148,2,32,214,73,157,224,
10879 18,128,98,29,241,69,65,50,37,241,116,200,41,144,102,125,2,180,8,210,152,38,
10880 129,23,8,34,198,
10881 };
10882 #endif  /* DUK_USE_ROM_STRINGS */
10883
10884 #if defined(DUK_USE_ROM_OBJECTS)
10885 #error ROM support not enabled, rerun configure.py with --rom-support
10886 #else  /* DUK_USE_ROM_OBJECTS */
10887 /* native functions: 177 */
10888 DUK_INTERNAL const duk_c_function duk_bi_native_functions[177] = {
10889         NULL,
10890         duk_bi_array_constructor,
10891         duk_bi_array_constructor_is_array,
10892         duk_bi_array_prototype_concat,
10893         duk_bi_array_prototype_indexof_shared,
10894         duk_bi_array_prototype_iter_shared,
10895         duk_bi_array_prototype_join_shared,
10896         duk_bi_array_prototype_pop,
10897         duk_bi_array_prototype_push,
10898         duk_bi_array_prototype_reduce_shared,
10899         duk_bi_array_prototype_reverse,
10900         duk_bi_array_prototype_shift,
10901         duk_bi_array_prototype_slice,
10902         duk_bi_array_prototype_sort,
10903         duk_bi_array_prototype_splice,
10904         duk_bi_array_prototype_to_string,
10905         duk_bi_array_prototype_unshift,
10906         duk_bi_arraybuffer_constructor,
10907         duk_bi_arraybuffer_isview,
10908         duk_bi_boolean_constructor,
10909         duk_bi_boolean_prototype_tostring_shared,
10910         duk_bi_buffer_compare_shared,
10911         duk_bi_buffer_readfield,
10912         duk_bi_buffer_slice_shared,
10913         duk_bi_buffer_writefield,
10914         duk_bi_dataview_constructor,
10915         duk_bi_date_constructor,
10916         duk_bi_date_constructor_now,
10917         duk_bi_date_constructor_parse,
10918         duk_bi_date_constructor_utc,
10919         duk_bi_date_prototype_get_shared,
10920         duk_bi_date_prototype_get_timezone_offset,
10921         duk_bi_date_prototype_set_shared,
10922         duk_bi_date_prototype_set_time,
10923         duk_bi_date_prototype_to_json,
10924         duk_bi_date_prototype_tostring_shared,
10925         duk_bi_date_prototype_value_of,
10926         duk_bi_duktape_object_act,
10927         duk_bi_duktape_object_compact,
10928         duk_bi_duktape_object_dec,
10929         duk_bi_duktape_object_enc,
10930         duk_bi_duktape_object_fin,
10931         duk_bi_duktape_object_gc,
10932         duk_bi_duktape_object_info,
10933         duk_bi_error_constructor_shared,
10934         duk_bi_error_prototype_filename_getter,
10935         duk_bi_error_prototype_filename_setter,
10936         duk_bi_error_prototype_linenumber_getter,
10937         duk_bi_error_prototype_linenumber_setter,
10938         duk_bi_error_prototype_stack_getter,
10939         duk_bi_error_prototype_stack_setter,
10940         duk_bi_error_prototype_to_string,
10941         duk_bi_function_constructor,
10942         duk_bi_function_prototype,
10943         duk_bi_function_prototype_apply,
10944         duk_bi_function_prototype_bind,
10945         duk_bi_function_prototype_call,
10946         duk_bi_function_prototype_to_string,
10947         duk_bi_global_object_decode_uri,
10948         duk_bi_global_object_decode_uri_component,
10949         duk_bi_global_object_encode_uri,
10950         duk_bi_global_object_encode_uri_component,
10951         duk_bi_global_object_escape,
10952         duk_bi_global_object_eval,
10953         duk_bi_global_object_is_finite,
10954         duk_bi_global_object_is_nan,
10955         duk_bi_global_object_parse_float,
10956         duk_bi_global_object_parse_int,
10957         duk_bi_global_object_unescape,
10958         duk_bi_json_object_parse,
10959         duk_bi_json_object_stringify,
10960         duk_bi_math_object_clz32,
10961         duk_bi_math_object_hypot,
10962         duk_bi_math_object_imul,
10963         duk_bi_math_object_max,
10964         duk_bi_math_object_min,
10965         duk_bi_math_object_onearg_shared,
10966         duk_bi_math_object_random,
10967         duk_bi_math_object_sign,
10968         duk_bi_math_object_twoarg_shared,
10969         duk_bi_native_function_length,
10970         duk_bi_native_function_name,
10971         duk_bi_nodejs_buffer_byte_length,
10972         duk_bi_nodejs_buffer_concat,
10973         duk_bi_nodejs_buffer_constructor,
10974         duk_bi_nodejs_buffer_copy,
10975         duk_bi_nodejs_buffer_fill,
10976         duk_bi_nodejs_buffer_is_buffer,
10977         duk_bi_nodejs_buffer_is_encoding,
10978         duk_bi_nodejs_buffer_tojson,
10979         duk_bi_nodejs_buffer_tostring,
10980         duk_bi_nodejs_buffer_write,
10981         duk_bi_number_check_shared,
10982         duk_bi_number_constructor,
10983         duk_bi_number_prototype_to_exponential,
10984         duk_bi_number_prototype_to_fixed,
10985         duk_bi_number_prototype_to_locale_string,
10986         duk_bi_number_prototype_to_precision,
10987         duk_bi_number_prototype_to_string,
10988         duk_bi_number_prototype_value_of,
10989         duk_bi_object_constructor,
10990         duk_bi_object_constructor_assign,
10991         duk_bi_object_constructor_create,
10992         duk_bi_object_constructor_define_properties,
10993         duk_bi_object_constructor_define_property,
10994         duk_bi_object_constructor_get_own_property_descriptor,
10995         duk_bi_object_constructor_is,
10996         duk_bi_object_constructor_is_extensible,
10997         duk_bi_object_constructor_is_sealed_frozen_shared,
10998         duk_bi_object_constructor_keys_shared,
10999         duk_bi_object_constructor_prevent_extensions,
11000         duk_bi_object_constructor_seal_freeze_shared,
11001         duk_bi_object_getprototype_shared,
11002         duk_bi_object_prototype_defineaccessor,
11003         duk_bi_object_prototype_has_own_property,
11004         duk_bi_object_prototype_is_prototype_of,
11005         duk_bi_object_prototype_lookupaccessor,
11006         duk_bi_object_prototype_property_is_enumerable,
11007         duk_bi_object_prototype_to_locale_string,
11008         duk_bi_object_prototype_to_string,
11009         duk_bi_object_prototype_value_of,
11010         duk_bi_object_setprototype_shared,
11011         duk_bi_performance_now,
11012         duk_bi_pointer_constructor,
11013         duk_bi_pointer_prototype_tostring_shared,
11014         duk_bi_proxy_constructor,
11015         duk_bi_reflect_apply,
11016         duk_bi_reflect_construct,
11017         duk_bi_reflect_object_delete_property,
11018         duk_bi_reflect_object_get,
11019         duk_bi_reflect_object_has,
11020         duk_bi_reflect_object_set,
11021         duk_bi_regexp_constructor,
11022         duk_bi_regexp_prototype_exec,
11023         duk_bi_regexp_prototype_flags,
11024         duk_bi_regexp_prototype_shared_getter,
11025         duk_bi_regexp_prototype_test,
11026         duk_bi_regexp_prototype_tostring,
11027         duk_bi_string_constructor,
11028         duk_bi_string_constructor_from_char_code,
11029         duk_bi_string_constructor_from_code_point,
11030         duk_bi_string_prototype_caseconv_shared,
11031         duk_bi_string_prototype_char_at,
11032         duk_bi_string_prototype_char_code_at,
11033         duk_bi_string_prototype_concat,
11034         duk_bi_string_prototype_includes,
11035         duk_bi_string_prototype_indexof_shared,
11036         duk_bi_string_prototype_locale_compare,
11037         duk_bi_string_prototype_match,
11038         duk_bi_string_prototype_repeat,
11039         duk_bi_string_prototype_replace,
11040         duk_bi_string_prototype_search,
11041         duk_bi_string_prototype_slice,
11042         duk_bi_string_prototype_split,
11043         duk_bi_string_prototype_startswith_endswith,
11044         duk_bi_string_prototype_substr,
11045         duk_bi_string_prototype_substring,
11046         duk_bi_string_prototype_to_string,
11047         duk_bi_string_prototype_trim,
11048         duk_bi_textdecoder_constructor,
11049         duk_bi_textdecoder_prototype_decode,
11050         duk_bi_textdecoder_prototype_shared_getter,
11051         duk_bi_textencoder_constructor,
11052         duk_bi_textencoder_prototype_encode,
11053         duk_bi_textencoder_prototype_encoding_getter,
11054         duk_bi_thread_constructor,
11055         duk_bi_thread_current,
11056         duk_bi_thread_resume,
11057         duk_bi_thread_yield,
11058         duk_bi_type_error_thrower,
11059         duk_bi_typedarray_buffer_getter,
11060         duk_bi_typedarray_bytelength_getter,
11061         duk_bi_typedarray_byteoffset_getter,
11062         duk_bi_typedarray_constructor,
11063         duk_bi_typedarray_set,
11064         duk_bi_uint8array_allocplain,
11065         duk_bi_uint8array_plainof,
11066 };
11067 #if defined(DUK_USE_DOUBLE_LE)
11068 DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = {
11069 144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243,
11070 124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33,
11071 167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
11072 64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
11073 142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
11074 242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
11075 1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
11076 33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198,
11077 174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32,
11078 248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215,
11079 128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170,
11080 154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130,
11081 249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145,
11082 136,67,134,19,49,0,0,0,0,0,0,3,225,255,51,0,0,0,0,0,0,3,193,255,47,18,1,
11083 172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240,
11084 149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,
11085 141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,
11086 132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42,
11087 96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242,
11088 243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53,
11089 79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47,
11090 147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139,
11091 121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8,
11092 151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147,
11093 180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52,
11094 78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52,
11095 146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194,
11096 70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31,
11097 55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64,
11098 96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36,
11099 103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178,
11100 1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17,
11101 46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200,
11102 217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140,
11103 241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250,
11104 96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81,
11105 46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104,
11106 194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8,
11107 109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71,
11108 240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173,
11109 174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40,
11110 104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32,
11111 194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62,
11112 16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150,
11113 129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179,
11114 224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255,
11115 248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128,
11116 124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34,
11117 131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231,
11118 192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107,
11119 255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19,
11120 245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161,
11121 163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132,
11122 5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13,
11123 34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80,
11124 211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39,
11125 22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221,
11126 197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2,
11127 127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64,
11128 132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46,
11129 190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,129,255,255,255,255,255,
11130 255,222,254,39,172,67,118,170,5,208,144,0,64,0,0,0,0,0,0,51,16,0,0,0,0,0,0,
11131 62,31,200,245,238,146,38,138,147,105,13,42,26,137,226,0,0,0,0,0,0,7,131,
11132 249,30,180,134,4,209,82,109,33,165,67,81,60,64,0,0,0,0,0,0,240,255,15,210,
11133 62,72,91,155,0,0,0,0,0,0,2,192,240,135,88,11,237,72,5,38,210,27,50,24,145,
11134 129,255,255,255,255,255,254,126,134,67,172,67,118,164,2,147,105,13,153,12,
11135 72,192,255,255,255,255,255,255,63,195,16,240,70,68,226,27,51,199,138,120,
11136 35,34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217,
11137 144,196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196,
11138 142,224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119,
11139 224,3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64,
11140 92,221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62,
11141 210,98,177,252,3,107,173,88,3,146,211,141,32,0,0,0,0,0,3,225,255,19,175,
11142 188,0,100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56,
11143 161,166,188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7,
11144 18,155,184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222,
11145 8,77,133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152,
11146 32,35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198,
11147 57,179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96,
11148 153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197,
11149 144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150,
11150 22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161,
11151 166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100,
11152 39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18,
11153 32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72,
11154 68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46,
11155 16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117,
11156 11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178,
11157 36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173,
11158 191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35,
11159 43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4,
11160 201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102,
11161 123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162,
11162 215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192,
11163 131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201,
11164 176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86,
11165 127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0,
11166 57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38,
11167 191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128,
11168 80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69,
11169 220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150,
11170 27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24,
11171 186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64,
11172 28,24,61,73,25,33,205,128,0,0,0,0,1,167,166,129,108,242,151,15,39,8,34,26,
11173 87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140,
11174 130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0,
11175 80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145,
11176 139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0,
11177 0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240,
11178 0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42,
11179 130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137,
11180 62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196,
11181 159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79,
11182 133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137,
11183 62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16,
11184 217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108,
11185 244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192,
11186 158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161,
11187 196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51,168,71,
11188 161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51,200,
11189 71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,7,129,249,155,51,
11190 232,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,155,52,
11191 8,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,2,1,155,52,40,
11192 71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155,52,72,
11193 71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155,52,
11194 104,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,0,130,1,155,
11195 52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,0,0,0,1,2,1,135,
11196 52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44,
11197 50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209,
11198 214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15,
11199 136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40,
11200 161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75,
11201 171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110,
11202 4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129,
11203 89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209,
11204 29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134,
11205 207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136,
11206 235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29,
11207 108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146,
11208 155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54,
11209 122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134,
11210 218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79,
11211 75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162,
11212 137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209,
11213 131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232,
11214 73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68,
11215 117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100,
11216 226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1,
11217 114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45,
11218 162,137,147,111,2,8,4,16,7,8,96,120,72,13,42,226,145,97,87,224,168,1,58,
11219 182,232,232,64,22,85,181,187,177,107,2,64,7,213,183,74,7,121,207,215,242,
11220 17,119,49,248,94,173,198,210,36,15,232,34,182,84,113,95,115,240,221,91,141,
11221 163,160,72,1,220,164,194,175,121,123,103,224,186,244,64,24,45,68,84,251,33,
11222 9,64,15,217,66,51,209,218,210,129,154,118,254,205,61,65,204,126,23,178,132,
11223 103,165,3,52,237,253,154,122,131,216,254,168,48,6,90,130,1,0,39,75,80,72,8,
11224 9,33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20,128,
11225 65,17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119,234,10,
11226 8,41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91,141,
11227 168,40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211,47,0,
11228 216,134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168,209,
11229 234,10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40,192,
11230 115,3,117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202,113,67,
11231 76,130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0,1,78,
11232 192,56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86,147,
11233 182,140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186,188,24,
11234 49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68,14,49,
11235 39,199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243,35,
11236 100,128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146,28,
11237 217,114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164,32,
11238 225,64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28,76,
11239 156,113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5,
11240 114,1,18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180,
11241 69,145,132,108,224,0,0,0,0,0,0,120,31,153,172,56,132,122,28,76,146,218,121,
11242 35,180,69,145,132,108,224,0,0,0,0,0,0,120,31,168,160,45,110,23,30,176,33,
11243 184,0,0,175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37,180,
11244 242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63,51,88,145,8,244,56,153,37,
11245 180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,88,161,8,244,56,153,37,
11246 180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,0,64,51,88,177,8,244,56,153,37,
11247 180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,193,8,244,56,153,
11248 37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,209,8,244,56,
11249 153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,16,64,51,88,225,8,244,
11250 56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,32,64,32,227,194,0,
11251 97,57,162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73,
11252 29,153,1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58,
11253 112,28,211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73,
11254 240,117,32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32,
11255 148,25,174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173,
11256 214,3,192,
11257 };
11258 #elif defined(DUK_USE_DOUBLE_BE)
11259 DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = {
11260 144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243,
11261 124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33,
11262 167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
11263 64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
11264 142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
11265 242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
11266 1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
11267 33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198,
11268 174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32,
11269 248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215,
11270 128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170,
11271 154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130,
11272 249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145,
11273 136,67,134,19,49,1,255,224,0,0,0,0,0,3,51,1,255,192,0,0,0,0,0,3,47,18,1,
11274 172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240,
11275 149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,
11276 141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,
11277 132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42,
11278 96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242,
11279 243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53,
11280 79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47,
11281 147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139,
11282 121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8,
11283 151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147,
11284 180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52,
11285 78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52,
11286 146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194,
11287 70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31,
11288 55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64,
11289 96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36,
11290 103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178,
11291 1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17,
11292 46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200,
11293 217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140,
11294 241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250,
11295 96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81,
11296 46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104,
11297 194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8,
11298 109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71,
11299 240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173,
11300 174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40,
11301 104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32,
11302 194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62,
11303 16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150,
11304 129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179,
11305 224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255,
11306 248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128,
11307 124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34,
11308 131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231,
11309 192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107,
11310 255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19,
11311 245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161,
11312 163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132,
11313 5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13,
11314 34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80,
11315 211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39,
11316 22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221,
11317 197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2,
11318 127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64,
11319 132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46,
11320 190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,128,255,223,255,255,255,
11321 255,255,254,39,172,67,118,170,5,208,144,0,0,0,0,0,0,0,0,115,16,31,254,0,0,
11322 0,0,0,0,8,245,238,146,38,138,147,105,13,42,26,137,226,3,255,128,0,0,0,0,0,
11323 1,30,180,134,4,209,82,109,33,165,67,81,60,64,255,240,0,0,0,0,0,0,15,210,62,
11324 72,91,155,0,242,192,0,0,0,0,0,0,135,88,11,237,72,5,38,210,27,50,24,145,128,
11325 134,127,255,255,255,255,255,254,67,172,67,118,164,2,147,105,13,153,12,72,
11326 192,195,63,255,255,255,255,255,255,16,240,70,68,226,27,51,199,138,120,35,
11327 34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217,144,
11328 196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196,142,
11329 224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119,224,
11330 3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64,92,
11331 221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62,210,
11332 98,177,252,3,107,173,88,3,146,211,141,33,255,224,0,0,0,0,0,3,19,175,188,0,
11333 100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56,161,166,
11334 188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7,18,155,
11335 184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222,8,77,
11336 133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152,32,
11337 35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198,57,
11338 179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96,
11339 153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197,
11340 144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150,
11341 22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161,
11342 166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100,
11343 39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18,
11344 32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72,
11345 68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46,
11346 16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117,
11347 11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178,
11348 36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173,
11349 191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35,
11350 43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4,
11351 201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102,
11352 123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162,
11353 215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192,
11354 131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201,
11355 176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86,
11356 127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0,
11357 57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38,
11358 191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128,
11359 80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69,
11360 220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150,
11361 27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24,
11362 186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64,
11363 28,24,61,73,25,33,205,128,129,167,166,0,0,0,0,1,108,242,151,15,39,8,34,26,
11364 87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140,
11365 130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0,
11366 80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145,
11367 139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0,
11368 0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240,
11369 0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42,
11370 130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137,
11371 62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196,
11372 159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79,
11373 133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137,
11374 62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16,
11375 217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108,
11376 244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192,
11377 158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161,
11378 196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51,168,71,
11379 161,196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51,200,
11380 71,161,196,201,45,167,146,59,68,89,24,70,206,1,255,128,0,0,0,0,0,1,155,51,
11381 232,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,0,0,0,0,0,0,1,155,52,
11382 8,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,0,0,0,0,0,0,1,155,52,40,
11383 71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155,52,72,
11384 71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155,52,
11385 104,71,161,196,201,45,167,146,59,68,89,24,70,206,2,0,128,0,0,0,0,0,1,155,
11386 52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,2,1,0,0,0,0,0,0,1,135,
11387 52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44,
11388 50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209,
11389 214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15,
11390 136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40,
11391 161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75,
11392 171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110,
11393 4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129,
11394 89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209,
11395 29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134,
11396 207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136,
11397 235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29,
11398 108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146,
11399 155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54,
11400 122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134,
11401 218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79,
11402 75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162,
11403 137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209,
11404 131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232,
11405 73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68,
11406 117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100,
11407 226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1,
11408 114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45,
11409 162,137,147,111,2,8,4,16,7,8,96,120,72,8,0,183,225,81,98,138,237,33,58,182,
11410 232,232,64,64,2,107,177,187,181,85,22,7,213,183,74,1,255,49,114,23,247,209,
11411 207,120,94,173,198,210,36,3,255,113,84,118,82,184,47,224,221,91,141,163,
11412 160,72,7,251,121,111,98,164,220,161,192,186,244,64,64,9,33,251,84,68,45,24,
11413 15,217,66,51,209,218,210,128,127,205,65,60,204,254,119,154,23,178,132,103,
11414 165,0,255,218,130,121,153,252,239,54,168,48,6,90,130,1,0,39,75,80,72,8,9,
11415 33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20,128,65,
11416 17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119,234,10,8,
11417 41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91,141,168,
11418 40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211,47,0,216,
11419 134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168,209,234,
11420 10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40,192,115,3,
11421 117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202,113,67,76,
11422 130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0,1,78,192,
11423 56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86,147,182,
11424 140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186,188,24,49,
11425 39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68,14,49,39,
11426 199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243,35,100,
11427 128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146,28,217,
11428 114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164,32,225,
11429 64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28,76,156,
11430 113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5,114,1,
11431 18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180,69,145,
11432 132,108,224,31,248,0,0,0,0,0,0,25,172,56,132,122,28,76,146,218,121,35,180,
11433 69,145,132,108,224,31,248,0,0,0,0,0,0,40,160,45,110,23,30,176,33,184,0,0,
11434 175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37,180,242,71,
11435 104,139,35,8,217,192,63,240,0,0,0,0,0,0,51,88,145,8,244,56,153,37,180,242,
11436 71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,88,161,8,244,56,153,37,180,242,
11437 71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,51,88,177,8,244,56,153,37,180,242,
11438 71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,193,8,244,56,153,37,180,
11439 242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,209,8,244,56,153,37,
11440 180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,0,0,51,88,225,8,244,56,153,
11441 37,180,242,71,104,139,35,8,217,192,64,32,0,0,0,0,0,0,32,227,194,0,97,57,
11442 162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73,29,153,
11443 1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58,112,28,
11444 211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73,240,117,
11445 32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32,148,25,
11446 174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173,214,3,
11447 192,
11448 };
11449 #elif defined(DUK_USE_DOUBLE_ME)
11450 DUK_INTERNAL const duk_uint8_t duk_builtins_data[4116] = {
11451 144,148,105,224,32,68,52,228,62,12,104,200,165,132,52,167,194,138,105,243,
11452 124,57,28,211,57,18,64,52,238,126,44,138,111,171,241,164,19,87,129,30,33,
11453 167,16,145,159,8,211,136,9,225,42,5,240,145,139,163,163,8,211,136,10,228,
11454 64,211,19,132,140,93,29,56,70,156,64,119,34,66,146,36,104,137,194,70,46,
11455 142,172,35,78,32,47,146,195,102,11,240,145,139,163,175,8,211,136,9,228,240,
11456 242,112,145,139,163,179,8,211,136,8,237,34,130,118,49,116,118,225,26,48,0,
11457 1,82,29,201,158,46,183,39,135,147,132,140,93,16,132,76,66,33,8,66,16,132,
11458 33,8,66,26,179,233,97,167,60,150,34,33,154,112,0,1,75,247,35,79,95,237,198,
11459 174,200,47,31,23,95,17,13,51,19,35,93,68,216,209,128,0,10,208,174,79,15,32,
11460 248,8,196,24,8,107,192,0,5,106,118,27,94,0,0,43,83,227,94,0,0,43,84,46,215,
11461 128,0,10,213,28,198,188,0,0,86,169,100,53,224,0,2,181,79,85,175,0,0,21,170,
11462 154,45,120,0,0,173,85,217,107,192,0,5,106,182,243,86,193,106,52,127,130,
11463 249,50,94,124,35,68,225,146,49,13,31,186,23,201,146,243,224,200,39,12,145,
11464 136,67,134,19,49,0,0,3,225,252,0,0,0,3,51,0,0,3,193,252,0,0,0,3,47,18,1,
11465 172,19,120,71,10,25,196,136,113,162,156,136,199,42,57,204,144,115,132,240,
11466 149,2,248,72,197,209,58,2,185,16,52,196,225,35,23,68,233,14,228,72,82,68,
11467 141,17,56,72,197,209,58,130,249,44,54,96,191,9,24,186,39,88,79,39,135,147,
11468 132,140,93,19,176,35,180,138,9,216,197,209,59,82,79,35,40,242,65,248,58,42,
11469 96,121,14,232,94,62,46,190,15,42,31,145,33,86,65,76,242,214,143,73,48,242,
11470 243,79,49,56,243,115,207,57,64,243,180,79,61,72,243,244,207,65,80,244,53,
11471 79,69,88,244,98,30,8,200,156,67,102,120,241,79,4,100,78,21,110,4,207,32,47,
11472 147,37,231,194,52,78,25,34,122,81,124,153,47,62,12,130,112,201,19,211,139,
11473 121,34,87,69,128,104,137,239,83,18,238,108,165,2,162,92,104,56,220,233,1,8,
11474 151,10,134,162,100,206,16,18,50,9,195,39,105,20,101,136,18,25,4,225,147,
11475 180,138,5,215,49,238,105,27,60,185,1,36,104,156,50,118,145,70,96,129,34,52,
11476 78,25,59,72,160,93,115,30,230,145,179,204,144,12,73,8,15,38,104,128,138,52,
11477 146,16,30,77,1,0,2,11,132,193,198,36,248,248,186,110,158,30,78,56,188,194,
11478 70,183,170,136,48,98,79,142,179,120,248,185,228,140,241,193,146,66,138,31,
11479 55,71,138,128,153,137,62,58,205,227,226,231,146,51,199,26,6,18,92,146,64,
11480 96,74,72,51,120,43,192,97,68,128,153,56,72,7,12,133,67,73,199,197,207,36,
11481 103,142,35,2,3,33,80,210,113,241,115,201,25,160,146,225,160,9,34,1,124,178,
11482 1,139,18,19,36,229,146,8,190,36,169,27,62,18,243,35,100,135,54,92,162,2,17,
11483 46,72,128,89,7,200,32,33,18,225,98,236,145,188,130,64,196,75,132,188,200,
11484 217,32,43,39,28,128,69,19,18,228,144,42,98,79,142,179,120,248,185,228,140,
11485 241,201,97,129,114,229,201,37,2,68,184,200,1,147,93,159,153,213,34,235,250,
11486 96,48,157,32,24,94,160,1,199,4,184,235,55,143,139,158,72,207,28,226,3,81,
11487 46,62,46,155,167,135,147,142,47,60,129,71,197,207,36,103,142,34,92,35,104,
11488 194,68,1,89,58,36,8,109,109,12,133,67,73,195,18,115,36,118,182,185,168,8,
11489 109,109,12,133,67,73,201,18,115,36,118,182,185,168,130,27,91,75,115,149,71,
11490 240,196,156,201,29,173,174,129,2,27,91,75,115,149,71,242,68,156,201,29,173,
11491 174,129,34,12,16,28,128,62,191,42,3,71,146,68,4,16,22,188,161,240,16,40,
11492 104,242,103,196,16,93,158,125,96,110,115,235,64,131,16,16,58,37,192,70,32,
11493 194,144,114,25,67,95,40,6,18,8,32,48,156,209,2,108,124,96,224,144,6,247,62,
11494 16,0,143,164,143,12,248,15,18,84,145,145,34,128,11,35,160,179,140,0,44,150,
11495 129,18,58,0,146,116,103,32,128,105,61,104,17,36,175,1,232,217,29,5,156,179,
11496 224,58,26,50,95,142,43,159,64,181,130,83,226,26,50,95,142,43,159,192,7,255,
11497 248,41,42,72,226,1,160,18,78,97,32,26,64,114,186,60,32,4,120,6,148,13,128,
11498 124,3,76,12,84,46,100,140,3,78,13,18,14,130,36,67,232,23,18,14,130,39,34,
11499 131,30,113,15,224,3,255,253,6,48,40,194,197,204,224,142,8,240,78,25,60,231,
11500 192,210,197,204,224,156,50,113,238,67,103,232,62,28,138,156,104,82,170,107,
11501 255,32,48,191,144,1,132,112,71,128,159,168,128,161,28,17,224,156,50,112,19,
11502 245,144,22,39,12,156,123,144,217,240,19,245,146,3,9,205,16,39,236,62,3,161,
11503 163,37,248,226,251,141,1,107,4,167,196,52,100,191,28,95,113,164,13,91,132,
11504 5,147,130,115,30,8,147,222,64,43,1,49,31,224,64,60,72,245,128,68,249,32,13,
11505 34,2,34,63,204,128,89,45,2,39,209,0,89,61,104,159,213,0,153,80,50,156,80,
11506 211,126,16,11,155,184,183,88,145,224,129,34,122,64,17,155,184,183,8,11,39,
11507 22,235,18,60,16,36,79,72,1,115,119,40,247,146,60,16,36,79,72,32,140,221,
11508 197,184,64,89,57,71,188,145,224,129,34,122,65,1,39,20,51,244,0,52,72,242,2,
11509 127,18,2,165,48,70,114,229,145,51,253,141,1,4,104,229,203,34,103,251,26,64,
11510 132,52,75,160,201,47,105,160,26,84,12,167,31,186,8,50,0,114,58,113,163,46,
11511 190,120,35,11,60,4,25,68,81,61,96,47,181,80,46,132,129,255,255,222,255,255,
11512 255,255,254,39,172,67,118,170,5,208,144,0,0,0,0,0,64,0,0,51,16,0,0,62,31,
11513 192,0,0,0,8,245,238,146,38,138,147,105,13,42,26,137,226,0,0,7,131,248,0,0,
11514 0,1,30,180,134,4,209,82,109,33,165,67,81,60,64,0,0,240,255,0,0,0,0,15,210,
11515 62,72,91,155,0,0,2,192,240,0,0,0,0,135,88,11,237,72,5,38,210,27,50,24,145,
11516 129,255,254,126,135,255,255,255,254,67,172,67,118,164,2,147,105,13,153,12,
11517 72,192,255,255,63,195,255,255,255,255,16,240,70,68,226,27,51,199,138,120,
11518 35,34,112,171,112,38,121,7,16,137,112,168,106,38,77,193,1,40,151,16,217,
11519 144,196,142,224,144,21,18,227,65,198,238,9,67,81,46,72,5,39,16,217,144,196,
11520 142,224,152,228,148,227,64,0,0,0,0,0,0,0,0,131,175,223,16,194,111,8,97,119,
11521 224,3,205,220,42,46,65,238,200,13,155,184,75,189,205,35,102,128,47,116,64,
11522 92,221,199,196,130,68,144,230,239,72,65,152,12,21,224,140,137,92,128,62,
11523 210,98,177,252,3,107,173,88,3,146,211,141,32,0,3,225,252,0,0,0,3,19,175,
11524 188,0,100,221,193,130,100,228,167,20,52,215,129,3,38,238,77,12,39,37,56,
11525 161,166,188,10,194,94,6,18,155,184,183,8,11,39,6,9,147,146,156,80,211,94,7,
11526 18,155,184,183,8,11,39,38,134,19,146,156,80,211,94,8,12,53,224,130,195,222,
11527 8,77,133,210,24,91,224,3,152,147,228,208,194,95,0,44,196,159,11,69,175,152,
11528 32,35,100,33,135,24,147,237,38,34,246,139,95,48,64,70,200,68,8,49,39,198,
11529 57,179,61,144,138,22,98,79,180,152,153,215,54,103,178,17,129,204,73,240,96,
11530 153,44,132,112,163,18,125,164,196,62,130,100,178,18,1,140,73,240,96,197,
11531 144,146,18,98,79,180,152,135,208,98,200,74,8,49,39,195,186,145,149,144,150,
11532 22,98,79,180,152,143,215,82,50,178,19,2,140,73,241,136,109,38,73,89,9,161,
11533 166,36,251,73,137,157,67,105,50,74,200,78,10,49,39,201,16,78,104,229,100,
11534 39,134,152,147,237,38,41,116,130,115,71,43,33,64,60,196,159,24,133,173,18,
11535 32,156,209,202,200,81,18,49,39,218,76,76,234,22,180,72,130,115,71,43,33,72,
11536 68,196,159,38,134,19,46,105,56,226,150,68,157,160,1,228,73,242,104,97,46,
11537 16,31,34,79,140,66,214,137,16,78,104,229,108,169,137,72,147,237,38,38,117,
11538 11,90,36,65,57,163,149,178,168,21,34,79,146,32,156,209,202,218,250,161,178,
11539 36,251,73,138,93,32,156,209,202,218,250,193,82,36,248,196,54,147,36,173,
11540 191,174,27,34,79,180,152,153,212,54,147,36,173,191,176,17,34,79,135,117,35,
11541 43,115,236,133,200,147,237,38,35,245,212,140,173,207,180,15,34,79,131,4,
11542 201,108,173,133,72,147,237,38,33,244,19,37,178,184,17,34,79,140,115,102,
11543 123,107,238,133,200,147,237,38,38,117,205,153,237,175,188,23,34,79,133,162,
11544 215,204,16,17,182,254,248,116,137,62,210,98,47,104,181,243,4,4,109,191,192,
11545 131,152,147,230,8,8,217,12,16,60,137,62,96,128,141,178,193,160,206,1,201,
11546 176,113,146,0,0,0,0,0,0,0,0,49,185,252,65,137,207,227,37,215,207,227,12,86,
11547 127,24,152,188,254,49,88,33,46,65,120,72,4,153,37,63,33,13,127,148,4,26,0,
11548 57,62,6,228,163,228,74,86,215,62,55,28,110,179,226,113,70,223,62,47,24,38,
11549 191,30,2,125,32,40,20,87,114,41,225,42,5,240,145,139,163,145,41,68,250,128,
11550 80,41,174,228,85,200,129,166,39,9,24,186,57,18,148,79,172,5,2,170,238,69,
11551 220,137,10,72,145,162,39,9,24,186,57,18,148,79,176,5,2,186,238,69,124,150,
11552 27,48,95,132,140,93,28,137,74,39,218,2,129,101,119,34,158,79,15,39,9,24,
11553 186,57,18,148,79,184,5,2,218,238,69,29,164,80,78,198,46,142,68,165,16,64,
11554 28,24,61,73,25,33,205,128,1,167,166,128,0,0,0,1,108,242,151,15,39,8,34,26,
11555 87,97,200,3,0,167,129,32,8,194,195,16,6,84,55,10,60,3,35,69,132,30,1,140,
11556 130,193,143,1,196,230,60,2,158,8,131,153,64,115,42,46,191,176,8,194,246,0,
11557 80,5,220,193,95,6,234,5,100,225,35,23,71,35,6,228,140,93,29,180,55,108,145,
11558 139,163,182,112,52,107,67,76,56,3,153,132,20,28,76,156,89,26,105,158,62,0,
11559 0,42,193,2,201,104,17,41,34,156,204,176,160,226,100,226,200,211,76,241,240,
11560 0,1,86,2,131,137,147,142,41,100,73,199,192,0,5,96,6,13,10,82,70,62,0,0,42,
11561 130,88,115,18,124,67,103,177,69,49,129,6,36,249,68,54,123,20,82,216,65,137,
11562 62,33,179,209,214,162,152,208,147,18,124,162,27,61,29,106,41,112,32,196,
11563 159,16,217,233,233,81,76,112,73,137,62,81,13,158,158,149,20,186,20,98,79,
11564 133,91,129,61,61,42,41,120,40,196,159,10,183,2,122,218,148,82,248,60,137,
11565 62,33,179,216,166,216,192,137,18,124,162,27,61,138,109,108,34,68,159,16,
11566 217,232,235,83,108,104,76,137,62,81,13,158,142,181,54,184,17,34,79,136,108,
11567 244,244,169,182,56,38,68,159,40,134,207,79,74,155,93,10,145,39,194,173,192,
11568 158,158,149,54,188,21,34,79,133,91,129,61,109,74,109,125,155,51,136,71,161,
11569 196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51,168,71,
11570 161,196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51,200,
11571 71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,7,129,248,0,0,0,1,155,51,
11572 232,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,155,52,
11573 8,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,2,0,0,0,0,1,155,52,40,
11574 71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155,52,72,
11575 71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155,52,
11576 104,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,0,130,0,0,0,0,1,155,
11577 52,136,71,161,196,201,45,167,146,59,68,89,24,70,206,0,0,1,2,0,0,0,0,1,135,
11578 52,166,32,76,72,1,246,136,235,103,177,69,0,136,144,3,226,27,61,138,41,44,
11579 50,36,0,251,68,117,179,209,214,234,201,69,16,50,36,0,251,68,117,179,209,
11580 214,232,73,69,34,5,196,128,31,16,217,232,235,117,100,162,147,2,226,64,15,
11581 136,108,244,117,186,18,81,74,129,145,32,7,218,35,173,158,158,151,86,74,40,
11582 161,145,32,7,218,35,173,158,158,151,66,74,41,20,46,36,0,248,134,207,79,75,
11583 171,37,20,154,23,18,0,124,67,103,167,165,208,146,138,85,11,137,0,62,21,110,
11584 4,250,178,81,70,11,137,0,62,21,110,4,250,18,81,72,193,145,32,7,193,186,129,
11585 89,58,178,81,71,12,137,0,62,13,212,10,201,208,146,138,71,10,137,0,62,209,
11586 29,108,250,178,81,104,1,81,32,7,218,35,173,159,66,74,45,32,38,36,0,248,134,
11587 207,171,37,22,160,19,18,0,124,67,103,208,146,139,88,10,180,81,50,118,136,
11588 235,103,177,77,128,155,69,19,39,16,217,236,83,105,97,182,138,38,78,209,29,
11589 108,244,117,186,178,83,100,13,180,81,50,118,136,235,103,163,173,208,146,
11590 155,68,12,180,81,50,113,13,158,142,183,86,74,109,48,50,209,68,201,196,54,
11591 122,58,221,9,41,181,64,219,69,19,39,104,142,182,122,122,93,89,41,178,134,
11592 218,40,153,59,68,117,179,211,210,232,73,77,162,134,90,40,153,56,134,207,79,
11593 75,171,37,54,154,25,104,162,100,226,27,61,61,46,132,148,218,168,101,162,
11594 137,147,133,91,129,62,172,148,217,131,45,20,76,156,42,220,9,244,36,166,209,
11595 131,109,20,76,156,27,168,21,147,171,37,54,112,219,69,19,39,6,234,5,100,232,
11596 73,77,163,133,218,40,153,59,68,117,179,234,201,78,32,5,218,40,153,59,68,
11597 117,179,232,73,78,36,5,90,40,153,56,134,207,171,37,56,160,21,104,162,100,
11598 226,27,62,132,148,226,195,95,182,97,176,218,128,8,84,45,123,38,1,137,10,1,
11599 114,160,64,56,156,199,130,36,160,72,8,39,63,27,24,1,100,180,8,148,146,0,45,
11600 162,137,147,111,2,8,4,16,7,8,96,120,72,1,87,224,168,13,42,226,145,97,58,
11601 182,232,232,64,177,107,2,64,22,85,181,187,7,213,183,74,2,17,119,49,255,121,
11602 207,215,240,94,173,198,210,36,4,113,95,115,255,232,34,182,80,221,91,141,
11603 163,160,72,15,121,123,103,225,220,164,194,160,186,244,64,251,33,9,64,24,45,
11604 68,84,15,217,66,51,209,218,210,129,61,65,204,127,154,118,254,204,23,178,
11605 132,103,165,2,122,131,216,255,52,237,253,154,168,48,6,90,130,1,0,39,75,80,
11606 72,8,9,33,186,130,80,64,76,13,212,19,2,130,96,110,150,173,0,65,6,51,212,20,
11607 128,65,17,11,212,19,130,137,121,211,210,209,144,6,39,75,80,80,0,201,119,
11608 234,10,8,41,86,231,71,80,80,129,79,135,186,122,69,224,34,25,69,233,80,3,91,
11609 141,168,40,96,139,113,180,181,5,36,21,110,54,142,134,160,165,1,176,23,211,
11610 47,0,216,134,233,215,128,111,117,181,104,128,209,3,70,230,106,64,5,139,168,
11611 209,234,10,32,36,144,102,234,136,3,146,27,168,40,160,146,132,103,168,40,
11612 192,115,3,117,5,28,22,113,163,69,168,41,103,1,66,188,17,145,52,40,4,202,
11613 113,67,76,130,227,68,194,13,240,108,0,0,83,96,0,2,161,0,104,146,84,97,48,0,
11614 1,78,192,56,169,24,145,179,192,0,5,48,8,56,16,32,128,56,18,52,125,166,86,
11615 147,182,140,28,50,21,13,39,31,23,60,145,158,56,140,141,47,113,6,155,186,
11616 188,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,155,163,197,68,
11617 14,49,39,199,197,211,116,240,242,113,197,230,18,180,253,228,3,17,46,18,243,
11618 35,100,128,172,156,114,70,163,146,76,34,248,146,164,108,248,75,204,141,146,
11619 28,217,114,137,27,78,251,241,173,234,162,160,225,1,3,34,92,170,9,105,164,
11620 32,225,64,131,155,1,193,133,7,19,39,22,70,154,103,143,128,0,10,176,20,28,
11621 76,156,113,75,34,78,62,0,0,43,0,48,104,82,146,49,240,0,1,84,11,180,192,0,5,
11622 114,1,18,160,65,24,131,20,145,25,172,48,132,122,28,76,146,218,121,35,180,
11623 69,145,132,108,224,0,0,120,31,128,0,0,0,25,172,56,132,122,28,76,146,218,
11624 121,35,180,69,145,132,108,224,0,0,120,31,128,0,0,0,40,160,45,110,23,30,176,
11625 33,184,0,0,175,32,29,235,2,27,199,23,0,0,22,4,51,88,129,8,244,56,153,37,
11626 180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0,51,88,145,8,244,56,153,
11627 37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,88,161,8,244,56,153,
11628 37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,0,0,51,88,177,8,244,56,153,
11629 37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,193,8,244,56,
11630 153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,209,8,244,
11631 56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,0,0,0,0,51,88,225,8,
11632 244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,32,64,0,0,0,0,32,227,194,
11633 0,97,57,162,4,245,232,5,34,92,35,68,225,161,166,218,16,16,137,112,52,41,73,
11634 29,153,1,65,196,201,197,145,166,153,245,200,3,137,204,120,34,74,8,200,58,
11635 112,28,211,32,130,52,78,26,26,110,248,0,0,164,4,12,70,137,195,39,252,73,
11636 240,117,32,57,168,97,4,104,156,52,52,221,255,160,20,160,152,23,223,250,32,
11637 148,25,174,137,58,23,51,191,244,84,12,50,9,195,39,240,81,238,2,3,107,173,
11638 214,3,192,
11639 };
11640 #else
11641 #error invalid endianness defines
11642 #endif
11643 #endif  /* DUK_USE_ROM_OBJECTS */
11644
11645 /* automatic undefs */
11646 #undef DUK__REFCINIT
11647 #line 1 "duk_error_macros.c"
11648 /*
11649  *  Error and fatal handling.
11650  */
11651
11652 /* #include duk_internal.h -> already included */
11653
11654 #define DUK__ERRFMT_BUFSIZE  256  /* size for formatting buffers */
11655
11656 #if defined(DUK_USE_VERBOSE_ERRORS)
11657
11658 DUK_INTERNAL DUK_COLD void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
11659         va_list ap;
11660         char msg[DUK__ERRFMT_BUFSIZE];
11661         va_start(ap, fmt);
11662         (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
11663         msg[sizeof(msg) - 1] = (char) 0;
11664         duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
11665         va_end(ap);  /* dead code, but ensures portability (see Linux man page notes) */
11666 }
11667
11668 DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
11669         duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
11670 }
11671
11672 #else  /* DUK_USE_VERBOSE_ERRORS */
11673
11674 DUK_INTERNAL DUK_COLD void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
11675         duk_err_create_and_throw(thr, code);
11676 }
11677
11678 #endif  /* DUK_USE_VERBOSE_ERRORS */
11679
11680 /*
11681  *  Error throwing helpers
11682  */
11683
11684 #if defined(DUK_USE_VERBOSE_ERRORS)
11685 #if defined(DUK_USE_PARANOID_ERRORS)
11686 DUK_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) {
11687         DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
11688                            expect_name, duk_get_type_name(thr, idx), (long) idx);
11689 }
11690 #else
11691 DUK_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) {
11692         DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
11693                            expect_name, duk_push_string_readable(thr, idx), (long) idx);
11694 }
11695 #endif
11696 DUK_INTERNAL DUK_COLD void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11697         DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR);
11698 }
11699 DUK_INTERNAL DUK_COLD void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11700         DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED);
11701 }
11702 DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
11703         DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message);
11704 }
11705 DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
11706         DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
11707 }
11708 DUK_INTERNAL DUK_COLD void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) {
11709         DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld", (long) (idx));
11710 }
11711 DUK_INTERNAL DUK_COLD void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11712         DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
11713 }
11714 DUK_INTERNAL DUK_COLD void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11715         DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS);
11716 }
11717 DUK_INTERNAL DUK_COLD void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11718         DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE);
11719 }
11720 DUK_INTERNAL DUK_COLD void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
11721         DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT);
11722 }
11723 #else
11724 /* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
11725  * when non-verbose errors are used.
11726  */
11727
11728 DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_errcode_t code));
11729 DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_errcode_t code) {
11730         DUK_ERROR_RAW(thr, NULL, 0, code, NULL);
11731 }
11732 DUK_INTERNAL DUK_COLD void duk_err_error(duk_hthread *thr) {
11733         duk__err_shared(thr, DUK_ERR_ERROR);
11734 }
11735 DUK_INTERNAL DUK_COLD void duk_err_range(duk_hthread *thr) {
11736         duk__err_shared(thr, DUK_ERR_RANGE_ERROR);
11737 }
11738 DUK_INTERNAL DUK_COLD void duk_err_eval(duk_hthread *thr) {
11739         duk__err_shared(thr, DUK_ERR_EVAL_ERROR);
11740 }
11741 DUK_INTERNAL DUK_COLD void duk_err_reference(duk_hthread *thr) {
11742         duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR);
11743 }
11744 DUK_INTERNAL DUK_COLD void duk_err_syntax(duk_hthread *thr) {
11745         duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR);
11746 }
11747 DUK_INTERNAL DUK_COLD void duk_err_type(duk_hthread *thr) {
11748         duk__err_shared(thr, DUK_ERR_TYPE_ERROR);
11749 }
11750 DUK_INTERNAL DUK_COLD void duk_err_uri(duk_hthread *thr) {
11751         duk__err_shared(thr, DUK_ERR_URI_ERROR);
11752 }
11753 #endif
11754
11755 /*
11756  *  Default fatal error handler
11757  */
11758
11759 DUK_INTERNAL DUK_COLD void duk_default_fatal_handler(void *udata, const char *msg) {
11760         DUK_UNREF(udata);
11761         DUK_UNREF(msg);
11762
11763         msg = msg ? msg : "NULL";
11764
11765 #if defined(DUK_USE_FATAL_HANDLER)
11766         /* duk_config.h provided a custom default fatal handler. */
11767         DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg));
11768         DUK_USE_FATAL_HANDLER(udata, msg);
11769 #elif defined(DUK_USE_CPP_EXCEPTIONS)
11770         /* With C++ use a duk_fatal_exception which user code can catch in
11771          * a natural way.
11772          */
11773         DUK_D(DUK_DPRINT("built-in default C++ fatal error handler called: %s", msg));
11774         throw duk_fatal_exception(msg);
11775 #else
11776         /* Default behavior is to abort() on error.  There's no printout
11777          * which makes this awkward, so it's always recommended to use an
11778          * explicit fatal error handler.
11779          *
11780          * ====================================================================
11781          * NOTE: If you are seeing this, you are most likely dealing with an
11782          * uncaught error.  You should provide a fatal error handler in Duktape
11783          * heap creation, and should consider using a protected call as your
11784          * first call into an empty Duktape context to properly handle errors.
11785          * See:
11786          *   - http://duktape.org/guide.html#error-handling
11787          *   - http://wiki.duktape.org/HowtoFatalErrors.html
11788          *   - http://duktape.org/api.html#taglist-protected
11789          * ====================================================================
11790          */
11791         DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg));
11792         DUK_ABORT();
11793 #endif
11794
11795         DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop"));
11796         for (;;) {
11797                 /* Loop forever to ensure we don't return. */
11798         }
11799 }
11800
11801 /* automatic undefs */
11802 #undef DUK__ERRFMT_BUFSIZE
11803 #line 1 "duk_unicode_support.c"
11804 /*
11805  *  Various Unicode help functions for character classification predicates,
11806  *  case conversion, decoding, etc.
11807  */
11808
11809 /* #include duk_internal.h -> already included */
11810
11811 /*
11812  *  Fast path tables
11813  */
11814
11815 #if defined(DUK_USE_IDCHAR_FASTPATH)
11816 DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = {
11817         /* 0: not IdentifierStart or IdentifierPart
11818          * 1: IdentifierStart and IdentifierPart
11819          * -1: IdentifierPart only
11820          */
11821         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   /* 0x00...0x0f */
11822         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   /* 0x10...0x1f */
11823         0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   /* 0x20...0x2f */
11824         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0,  0,  0,  0,  0,  0,   /* 0x30...0x3f */
11825         0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,   /* 0x40...0x4f */
11826         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  1,   /* 0x50...0x5f */
11827         0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,   /* 0x60...0x6f */
11828         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0    /* 0x70...0x7f */
11829 };
11830 #endif
11831
11832 /*
11833  *  XUTF-8 and CESU-8 encoding/decoding
11834  */
11835
11836 DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) {
11837         duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
11838         if (x < 0x80UL) {
11839                 /* 7 bits */
11840                 return 1;
11841         } else if (x < 0x800UL) {
11842                 /* 11 bits */
11843                 return 2;
11844         } else if (x < 0x10000UL) {
11845                 /* 16 bits */
11846                 return 3;
11847         } else if (x < 0x200000UL) {
11848                 /* 21 bits */
11849                 return 4;
11850         } else if (x < 0x4000000UL) {
11851                 /* 26 bits */
11852                 return 5;
11853         } else if (x < (duk_ucodepoint_t) 0x80000000UL) {
11854                 /* 31 bits */
11855                 return 6;
11856         } else {
11857                 /* 36 bits */
11858                 return 7;
11859         }
11860 }
11861
11862 #if defined(DUK_USE_ASSERTIONS)
11863 DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) {
11864         duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
11865         if (x < 0x80UL) {
11866                 /* 7 bits */
11867                 return 1;
11868         } else if (x < 0x800UL) {
11869                 /* 11 bits */
11870                 return 2;
11871         } else if (x < 0x10000UL) {
11872                 /* 16 bits */
11873                 return 3;
11874         } else {
11875                 /* Encoded as surrogate pair, each encoding to 3 bytes for
11876                  * 6 bytes total.  Codepoints above U+10FFFF encode as 6 bytes
11877                  * too, see duk_unicode_encode_cesu8().
11878                   */
11879                 return 3 + 3;
11880         }
11881 }
11882 #endif  /* DUK_USE_ASSERTIONS */
11883
11884 DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = {
11885         0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
11886 };
11887
11888 /* Encode to extended UTF-8; 'out' must have space for at least
11889  * DUK_UNICODE_MAX_XUTF8_LENGTH bytes.  Allows encoding of any
11890  * 32-bit (unsigned) codepoint.
11891  */
11892 DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) {
11893         duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
11894         duk_small_int_t len;
11895         duk_uint8_t marker;
11896         duk_small_int_t i;
11897
11898         len = duk_unicode_get_xutf8_length(cp);
11899         DUK_ASSERT(len > 0);
11900
11901         marker = duk_unicode_xutf8_markers[len - 1];  /* 64-bit OK because always >= 0 */
11902
11903         i = len;
11904         DUK_ASSERT(i > 0);
11905         do {
11906                 i--;
11907                 if (i > 0) {
11908                         out[i] = (duk_uint8_t) (0x80 + (x & 0x3f));
11909                         x >>= 6;
11910                 } else {
11911                         /* Note: masking of 'x' is not necessary because of
11912                          * range check and shifting -> no bits overlapping
11913                          * the marker should be set.
11914                          */
11915                         out[0] = (duk_uint8_t) (marker + x);
11916                 }
11917         } while (i > 0);
11918
11919         return len;
11920 }
11921
11922 /* Encode to CESU-8; 'out' must have space for at least
11923  * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF
11924  * will encode to garbage but won't overwrite the output buffer.
11925  */
11926 DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) {
11927         duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
11928         duk_small_int_t len;
11929
11930         if (x < 0x80UL) {
11931                 out[0] = (duk_uint8_t) x;
11932                 len = 1;
11933         } else if (x < 0x800UL) {
11934                 out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f));
11935                 out[1] = (duk_uint8_t) (0x80 + (x & 0x3f));
11936                 len = 2;
11937         } else if (x < 0x10000UL) {
11938                 /* surrogate pairs get encoded here */
11939                 out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f));
11940                 out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f));
11941                 out[2] = (duk_uint8_t) (0x80 + (x & 0x3f));
11942                 len = 3;
11943         } else {
11944                 /*
11945                  *  Unicode codepoints above U+FFFF are encoded as surrogate
11946                  *  pairs here.  This ensures that all CESU-8 codepoints are
11947                  *  16-bit values as expected in ECMAScript.  The surrogate
11948                  *  pairs always get a 3-byte encoding (each) in CESU-8.
11949                  *  See: http://en.wikipedia.org/wiki/Surrogate_pair
11950                  *
11951                  *  20-bit codepoint, 10 bits (A and B) per surrogate pair:
11952                  *
11953                  *    x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB
11954                  *  sp1 = 0b110110AA AAAAAAAA  (0xd800 + ((x >> 10) & 0x3ff))
11955                  *  sp2 = 0b110111BB BBBBBBBB  (0xdc00 + (x & 0x3ff))
11956                  *
11957                  *  Encoded into CESU-8:
11958                  *
11959                  *  sp1 -> 0b11101101  (0xe0 + ((sp1 >> 12) & 0x0f))
11960                  *      -> 0b1010AAAA  (0x80 + ((sp1 >> 6) & 0x3f))
11961                  *      -> 0b10AAAAAA  (0x80 + (sp1 & 0x3f))
11962                  *  sp2 -> 0b11101101  (0xe0 + ((sp2 >> 12) & 0x0f))
11963                  *      -> 0b1011BBBB  (0x80 + ((sp2 >> 6) & 0x3f))
11964                  *      -> 0b10BBBBBB  (0x80 + (sp2 & 0x3f))
11965                  *
11966                  *  Note that 0x10000 must be subtracted first.  The code below
11967                  *  avoids the sp1, sp2 temporaries which saves around 20 bytes
11968                  *  of code.
11969                  */
11970
11971                 x -= 0x10000UL;
11972
11973                 out[0] = (duk_uint8_t) (0xed);
11974                 out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f));
11975                 out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f));
11976                 out[3] = (duk_uint8_t) (0xed);
11977                 out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f));
11978                 out[5] = (duk_uint8_t) (0x80 + (x & 0x3f));
11979                 len = 6;
11980         }
11981
11982         return len;
11983 }
11984
11985 /* Decode helper.  Return zero on error. */
11986 DUK_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) {
11987         const duk_uint8_t *p;
11988         duk_uint32_t res;
11989         duk_uint_fast8_t ch;
11990         duk_small_int_t n;
11991
11992         DUK_UNREF(thr);
11993
11994         p = *ptr;
11995         if (p < ptr_start || p >= ptr_end) {
11996                 goto fail;
11997         }
11998
11999         /*
12000          *  UTF-8 decoder which accepts longer than standard byte sequences.
12001          *  This allows full 32-bit code points to be used.
12002          */
12003
12004         ch = (duk_uint_fast8_t) (*p++);
12005         if (ch < 0x80) {
12006                 /* 0xxx xxxx   [7 bits] */
12007                 res = (duk_uint32_t) (ch & 0x7f);
12008                 n = 0;
12009         } else if (ch < 0xc0) {
12010                 /* 10xx xxxx -> invalid */
12011                 goto fail;
12012         } else if (ch < 0xe0) {
12013                 /* 110x xxxx   10xx xxxx   [11 bits] */
12014                 res = (duk_uint32_t) (ch & 0x1f);
12015                 n = 1;
12016         } else if (ch < 0xf0) {
12017                 /* 1110 xxxx   10xx xxxx   10xx xxxx   [16 bits] */
12018                 res = (duk_uint32_t) (ch & 0x0f);
12019                 n = 2;
12020         } else if (ch < 0xf8) {
12021                 /* 1111 0xxx   10xx xxxx   10xx xxxx   10xx xxxx   [21 bits] */
12022                 res = (duk_uint32_t) (ch & 0x07);
12023                 n = 3;
12024         } else if (ch < 0xfc) {
12025                 /* 1111 10xx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   [26 bits] */
12026                 res = (duk_uint32_t) (ch & 0x03);
12027                 n = 4;
12028         } else if (ch < 0xfe) {
12029                 /* 1111 110x   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   [31 bits] */
12030                 res = (duk_uint32_t) (ch & 0x01);
12031                 n = 5;
12032         } else if (ch < 0xff) {
12033                 /* 1111 1110   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   [36 bits] */
12034                 res = (duk_uint32_t) (0);
12035                 n = 6;
12036         } else {
12037                 /* 8-byte format could be:
12038                  * 1111 1111   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   10xx xxxx   [41 bits]
12039                  *
12040                  * However, this format would not have a zero bit following the
12041                  * leading one bits and would not allow 0xFF to be used as an
12042                  * "invalid xutf-8" marker for internal keys.  Further, 8-byte
12043                  * encodings (up to 41 bit code points) are not currently needed.
12044                  */
12045                 goto fail;
12046         }
12047
12048         DUK_ASSERT(p >= ptr_start);  /* verified at beginning */
12049         if (p + n > ptr_end) {
12050                 /* check pointer at end */
12051                 goto fail;
12052         }
12053
12054         while (n > 0) {
12055                 DUK_ASSERT(p >= ptr_start && p < ptr_end);
12056                 ch = (duk_uint_fast8_t) (*p++);
12057 #if 0
12058                 if (ch & 0xc0 != 0x80) {
12059                         /* not a continuation byte */
12060                         p--;
12061                         *ptr = p;
12062                         *out_cp = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
12063                         return 1;
12064                 }
12065 #endif
12066                 res = (res << 6) + (duk_uint32_t) (ch & 0x3f);
12067                 n--;
12068         }
12069
12070         *ptr = p;
12071         *out_cp = res;
12072         return 1;
12073
12074  fail:
12075         return 0;
12076 }
12077
12078 /* used by e.g. duk_regexp_executor.c, string built-ins */
12079 DUK_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) {
12080         duk_ucodepoint_t cp;
12081
12082         if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
12083                 return cp;
12084         }
12085         DUK_ERROR_INTERNAL(thr);
12086         DUK_WO_NORETURN(return 0;);
12087 }
12088
12089 /* Compute (extended) utf-8 length without codepoint encoding validation,
12090  * used for string interning.
12091  *
12092  * NOTE: This algorithm is performance critical, more so than string hashing
12093  * in some cases.  It is needed when interning a string and needs to scan
12094  * every byte of the string with no skipping.  Having an ASCII fast path
12095  * is useful if possible in the algorithm.  The current algorithms were
12096  * chosen from several variants, based on x64 gcc -O2 testing.  See:
12097  * https://github.com/svaarala/duktape/pull/422
12098  *
12099  * NOTE: must match tools/dukutil.py:duk_unicode_unvalidated_utf8_length().
12100  */
12101
12102 #if defined(DUK_USE_PREFER_SIZE)
12103 /* Small variant; roughly 150 bytes smaller than the fast variant. */
12104 DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
12105         const duk_uint8_t *p;
12106         const duk_uint8_t *p_end;
12107         duk_size_t ncont;
12108         duk_size_t clen;
12109
12110         p = data;
12111         p_end = data + blen;
12112         ncont = 0;
12113         while (p != p_end) {
12114                 duk_uint8_t x;
12115                 x = *p++;
12116                 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
12117                         ncont++;
12118                 }
12119         }
12120
12121         DUK_ASSERT(ncont <= blen);
12122         clen = blen - ncont;
12123         DUK_ASSERT(clen <= blen);
12124         return clen;
12125 }
12126 #else  /* DUK_USE_PREFER_SIZE */
12127 /* This seems like a good overall approach.  Fast path for ASCII in 4 byte
12128  * blocks.
12129  */
12130 DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
12131         const duk_uint8_t *p;
12132         const duk_uint8_t *p_end;
12133         const duk_uint32_t *p32_end;
12134         const duk_uint32_t *p32;
12135         duk_size_t ncont;
12136         duk_size_t clen;
12137
12138         ncont = 0;  /* number of continuation (non-initial) bytes in [0x80,0xbf] */
12139         p = data;
12140         p_end = data + blen;
12141         if (blen < 16) {
12142                 goto skip_fastpath;
12143         }
12144
12145         /* Align 'p' to 4; the input data may have arbitrary alignment.
12146          * End of string check not needed because blen >= 16.
12147          */
12148         while (((duk_size_t) (const void *) p) & 0x03U) {
12149                 duk_uint8_t x;
12150                 x = *p++;
12151                 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
12152                         ncont++;
12153                 }
12154         }
12155
12156         /* Full, aligned 4-byte reads. */
12157         p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03)));
12158         p32 = (const duk_uint32_t *) (const void *) p;
12159         while (p32 != (const duk_uint32_t *) p32_end) {
12160                 duk_uint32_t x;
12161                 x = *p32++;
12162                 if (DUK_LIKELY((x & 0x80808080UL) == 0)) {
12163                         ;  /* ASCII fast path */
12164                 } else {
12165                         /* Flip highest bit of each byte which changes
12166                          * the bit pattern 10xxxxxx into 00xxxxxx which
12167                          * allows an easy bit mask test.
12168                          */
12169                         x ^= 0x80808080UL;
12170                         if (DUK_UNLIKELY(!(x & 0xc0000000UL))) {
12171                                 ncont++;
12172                         }
12173                         if (DUK_UNLIKELY(!(x & 0x00c00000UL))) {
12174                                 ncont++;
12175                         }
12176                         if (DUK_UNLIKELY(!(x & 0x0000c000UL))) {
12177                                 ncont++;
12178                         }
12179                         if (DUK_UNLIKELY(!(x & 0x000000c0UL))) {
12180                                 ncont++;
12181                         }
12182                 }
12183         }
12184         p = (const duk_uint8_t *) p32;
12185         /* Fall through to handle the rest. */
12186
12187  skip_fastpath:
12188         while (p != p_end) {
12189                 duk_uint8_t x;
12190                 x = *p++;
12191                 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
12192                         ncont++;
12193                 }
12194         }
12195
12196         DUK_ASSERT(ncont <= blen);
12197         clen = blen - ncont;
12198         DUK_ASSERT(clen <= blen);
12199         return clen;
12200 }
12201 #endif  /* DUK_USE_PREFER_SIZE */
12202
12203 /*
12204  *  Unicode range matcher
12205  *
12206  *  Matches a codepoint against a packed bitstream of character ranges.
12207  *  Used for slow path Unicode matching.
12208  */
12209
12210 /* Must match tools/extract_chars.py, generate_match_table3(). */
12211 DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
12212         duk_uint32_t t;
12213
12214         t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4);
12215         if (t <= 0x0eU) {
12216                 return t;
12217         }
12218         t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8);
12219         if (t <= 0xfdU) {
12220                 return t + 0x0f;
12221         }
12222         if (t == 0xfeU) {
12223                 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12);
12224                 return t + 0x0fU + 0xfeU;
12225         } else {
12226                 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24);
12227                 return t + 0x0fU + 0xfeU + 0x1000UL;
12228         }
12229 }
12230
12231 DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) {
12232         duk_bitdecoder_ctx bd_ctx;
12233         duk_codepoint_t prev_re;
12234
12235         duk_memzero(&bd_ctx, sizeof(bd_ctx));
12236         bd_ctx.data = (const duk_uint8_t *) unitab;
12237         bd_ctx.length = (duk_size_t) unilen;
12238
12239         prev_re = 0;
12240         for (;;) {
12241                 duk_codepoint_t r1, r2;
12242                 r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
12243                 if (r1 == 0) {
12244                         break;
12245                 }
12246                 r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
12247
12248                 r1 = prev_re + r1;
12249                 r2 = r1 + r2;
12250                 prev_re = r2;
12251
12252                 /* [r1,r2] is the range */
12253
12254                 DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]",
12255                                      (unsigned long) cp, (unsigned long) r1, (unsigned long) r2));
12256                 if (cp >= r1 && cp <= r2) {
12257                         return 1;
12258                 }
12259         }
12260
12261         return 0;
12262 }
12263
12264 /*
12265  *  "WhiteSpace" production check.
12266  */
12267
12268 DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
12269         /*
12270          *  E5 Section 7.2 specifies six characters specifically as
12271          *  white space:
12272          *
12273          *    0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
12274          *    000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
12275          *    000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
12276          *    0020;SPACE;Zs;0;WS;;;;;N;;;;;
12277          *    00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
12278          *    FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
12279          *
12280          *  It also specifies any Unicode category 'Zs' characters as white
12281          *  space.  These can be extracted with the "tools/extract_chars.py" script.
12282          *  Current result:
12283          *
12284          *    RAW OUTPUT:
12285          *    ===========
12286          *    0020;SPACE;Zs;0;WS;;;;;N;;;;;
12287          *    00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
12288          *    1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
12289          *    180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
12290          *    2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
12291          *    2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
12292          *    2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12293          *    2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12294          *    2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12295          *    2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12296          *    2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12297          *    2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
12298          *    2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12299          *    2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12300          *    200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12301          *    202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
12302          *    205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
12303          *    3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
12304          *
12305          *    RANGES:
12306          *    =======
12307          *    0x0020
12308          *    0x00a0
12309          *    0x1680
12310          *    0x180e
12311          *    0x2000 ... 0x200a
12312          *    0x202f
12313          *    0x205f
12314          *    0x3000
12315          *
12316          *  A manual decoder (below) is probably most compact for this.
12317          */
12318
12319         duk_uint_fast8_t lo;
12320         duk_uint_fast32_t hi;
12321
12322         /* cp == -1 (EOF) never matches and causes return value 0 */
12323
12324         lo = (duk_uint_fast8_t) (cp & 0xff);
12325         hi = (duk_uint_fast32_t) (cp >> 8);  /* does not fit into an uchar */
12326
12327         if (hi == 0x0000UL) {
12328                 if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU ||
12329                     lo == 0x20U || lo == 0xa0U) {
12330                         return 1;
12331                 }
12332         } else if (hi == 0x0020UL) {
12333                 if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) {
12334                         return 1;
12335                 }
12336         } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L ||
12337                    cp == 0xfeffL) {
12338                 return 1;
12339         }
12340
12341         return 0;
12342 }
12343
12344 /*
12345  *  "LineTerminator" production check.
12346  */
12347
12348 DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) {
12349         /*
12350          *  E5 Section 7.3
12351          *
12352          *  A LineTerminatorSequence essentially merges <CR> <LF> sequences
12353          *  into a single line terminator.  This must be handled by the caller.
12354          */
12355
12356         if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L ||
12357             cp == 0x2029L) {
12358                 return 1;
12359         }
12360
12361         return 0;
12362 }
12363
12364 /*
12365  *  "IdentifierStart" production check.
12366  */
12367
12368 DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) {
12369         /*
12370          *  E5 Section 7.6:
12371          *
12372          *    IdentifierStart:
12373          *      UnicodeLetter
12374          *      $
12375          *      _
12376          *      \ UnicodeEscapeSequence
12377          *
12378          *  IdentifierStart production has one multi-character production:
12379          *
12380          *    \ UnicodeEscapeSequence
12381          *
12382          *  The '\' character is -not- matched by this function.  Rather, the caller
12383          *  should decode the escape and then call this function to check whether the
12384          *  decoded character is acceptable (see discussion in E5 Section 7.6).
12385          *
12386          *  The "UnicodeLetter" alternative of the production allows letters
12387          *  from various Unicode categories.  These can be extracted with the
12388          *  "tools/extract_chars.py" script.
12389          *
12390          *  Because the result has hundreds of Unicode codepoint ranges, matching
12391          *  for any values >= 0x80 are done using a very slow range-by-range scan
12392          *  and a packed range format.
12393          *
12394          *  The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because
12395          *  it matters the most.  The ASCII related ranges of IdentifierStart are:
12396          *
12397          *    0x0041 ... 0x005a     ['A' ... 'Z']
12398          *    0x0061 ... 0x007a     ['a' ... 'z']
12399          *    0x0024                ['$']
12400          *    0x005f                ['_']
12401          */
12402
12403         /* ASCII (and EOF) fast path -- quick accept and reject */
12404         if (cp <= 0x7fL) {
12405 #if defined(DUK_USE_IDCHAR_FASTPATH)
12406                 return (cp >= 0) && (duk_is_idchar_tab[cp] > 0);
12407 #else
12408                 if ((cp >= 'a' && cp <= 'z') ||
12409                     (cp >= 'A' && cp <= 'Z') ||
12410                     cp == '_' || cp == '$') {
12411                         return 1;
12412                 }
12413                 return 0;
12414 #endif
12415         }
12416
12417         /* Non-ASCII slow path (range-by-range linear comparison), very slow */
12418
12419 #if defined(DUK_USE_SOURCE_NONBMP)
12420         if (duk__uni_range_match(duk_unicode_ids_noa,
12421                                  (duk_size_t) sizeof(duk_unicode_ids_noa),
12422                                  (duk_codepoint_t) cp)) {
12423                 return 1;
12424         }
12425         return 0;
12426 #else
12427         if (cp < 0x10000L) {
12428                 if (duk__uni_range_match(duk_unicode_ids_noabmp,
12429                                          sizeof(duk_unicode_ids_noabmp),
12430                                          (duk_codepoint_t) cp)) {
12431                         return 1;
12432                 }
12433                 return 0;
12434         } else {
12435                 /* without explicit non-BMP support, assume non-BMP characters
12436                  * are always accepted as identifier characters.
12437                  */
12438                 return 1;
12439         }
12440 #endif
12441 }
12442
12443 /*
12444  *  "IdentifierPart" production check.
12445  */
12446
12447 DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) {
12448         /*
12449          *  E5 Section 7.6:
12450          *
12451          *    IdentifierPart:
12452          *      IdentifierStart
12453          *      UnicodeCombiningMark
12454          *      UnicodeDigit
12455          *      UnicodeConnectorPunctuation
12456          *      <ZWNJ>  [U+200C]
12457          *      <ZWJ>   [U+200D]
12458          *
12459          *  IdentifierPart production has one multi-character production
12460          *  as part of its IdentifierStart alternative.  The '\' character
12461          *  of an escape sequence is not matched here, see discussion in
12462          *  duk_unicode_is_identifier_start().
12463          *
12464          *  To match non-ASCII characters (codepoints >= 0x80), a very slow
12465          *  linear range-by-range scan is used.  The codepoint is first compared
12466          *  to the IdentifierStart ranges, and if it doesn't match, then to a
12467          *  set consisting of code points in IdentifierPart but not in
12468          *  IdentifierStart.  This is done to keep the unicode range data small,
12469          *  at the expense of speed.
12470          *
12471          *  The ASCII fast path consists of:
12472          *
12473          *    0x0030 ... 0x0039     ['0' ... '9', UnicodeDigit]
12474          *    0x0041 ... 0x005a     ['A' ... 'Z', IdentifierStart]
12475          *    0x0061 ... 0x007a     ['a' ... 'z', IdentifierStart]
12476          *    0x0024                ['$', IdentifierStart]
12477          *    0x005f                ['_', IdentifierStart and
12478          *                                UnicodeConnectorPunctuation]
12479          *
12480          *  UnicodeCombiningMark has no code points <= 0x7f.
12481          *
12482          *  The matching code reuses the "identifier start" tables, and then
12483          *  consults a separate range set for characters in "identifier part"
12484          *  but not in "identifier start".  These can be extracted with the
12485          *  "tools/extract_chars.py" script.
12486          *
12487          *  UnicodeCombiningMark -> categories Mn, Mc
12488          *  UnicodeDigit -> categories Nd
12489          *  UnicodeConnectorPunctuation -> categories Pc
12490          */
12491
12492         /* ASCII (and EOF) fast path -- quick accept and reject */
12493         if (cp <= 0x7fL) {
12494 #if defined(DUK_USE_IDCHAR_FASTPATH)
12495                 return (cp >= 0) && (duk_is_idchar_tab[cp] != 0);
12496 #else
12497                 if ((cp >= 'a' && cp <= 'z') ||
12498                     (cp >= 'A' && cp <= 'Z') ||
12499                     (cp >= '0' && cp <= '9') ||
12500                     cp == '_' || cp == '$') {
12501                         return 1;
12502                 }
12503                 return 0;
12504 #endif
12505         }
12506
12507         /* Non-ASCII slow path (range-by-range linear comparison), very slow */
12508
12509 #if defined(DUK_USE_SOURCE_NONBMP)
12510         if (duk__uni_range_match(duk_unicode_ids_noa,
12511                                  sizeof(duk_unicode_ids_noa),
12512                                  (duk_codepoint_t) cp) ||
12513             duk__uni_range_match(duk_unicode_idp_m_ids_noa,
12514                                  sizeof(duk_unicode_idp_m_ids_noa),
12515                                  (duk_codepoint_t) cp)) {
12516                 return 1;
12517         }
12518         return 0;
12519 #else
12520         if (cp < 0x10000L) {
12521                 if (duk__uni_range_match(duk_unicode_ids_noabmp,
12522                                          sizeof(duk_unicode_ids_noabmp),
12523                                          (duk_codepoint_t) cp) ||
12524                     duk__uni_range_match(duk_unicode_idp_m_ids_noabmp,
12525                                          sizeof(duk_unicode_idp_m_ids_noabmp),
12526                                          (duk_codepoint_t) cp)) {
12527                         return 1;
12528                 }
12529                 return 0;
12530         } else {
12531                 /* without explicit non-BMP support, assume non-BMP characters
12532                  * are always accepted as identifier characters.
12533                  */
12534                 return 1;
12535         }
12536 #endif
12537 }
12538
12539 /*
12540  *  Unicode letter check.
12541  */
12542
12543 DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
12544         /*
12545          *  Unicode letter is now taken to be the categories:
12546          *
12547          *    Lu, Ll, Lt, Lm, Lo
12548          *
12549          *  (Not sure if this is exactly correct.)
12550          *
12551          *  The ASCII fast path consists of:
12552          *
12553          *    0x0041 ... 0x005a     ['A' ... 'Z']
12554          *    0x0061 ... 0x007a     ['a' ... 'z']
12555          */
12556
12557         /* ASCII (and EOF) fast path -- quick accept and reject */
12558         if (cp <= 0x7fL) {
12559                 if ((cp >= 'a' && cp <= 'z') ||
12560                     (cp >= 'A' && cp <= 'Z')) {
12561                         return 1;
12562                 }
12563                 return 0;
12564         }
12565
12566         /* Non-ASCII slow path (range-by-range linear comparison), very slow */
12567
12568 #if defined(DUK_USE_SOURCE_NONBMP)
12569         if (duk__uni_range_match(duk_unicode_ids_noa,
12570                                  sizeof(duk_unicode_ids_noa),
12571                                  (duk_codepoint_t) cp) &&
12572             !duk__uni_range_match(duk_unicode_ids_m_let_noa,
12573                                   sizeof(duk_unicode_ids_m_let_noa),
12574                                   (duk_codepoint_t) cp)) {
12575                 return 1;
12576         }
12577         return 0;
12578 #else
12579         if (cp < 0x10000L) {
12580                 if (duk__uni_range_match(duk_unicode_ids_noabmp,
12581                                          sizeof(duk_unicode_ids_noabmp),
12582                                          (duk_codepoint_t) cp) &&
12583                     !duk__uni_range_match(duk_unicode_ids_m_let_noabmp,
12584                                           sizeof(duk_unicode_ids_m_let_noabmp),
12585                                           (duk_codepoint_t) cp)) {
12586                         return 1;
12587                 }
12588                 return 0;
12589         } else {
12590                 /* without explicit non-BMP support, assume non-BMP characters
12591                  * are always accepted as letters.
12592                  */
12593                 return 1;
12594         }
12595 #endif
12596 }
12597
12598 /*
12599  *  Complex case conversion helper which decodes a bit-packed conversion
12600  *  control stream generated by tools/extract_caseconv.py.  The conversion
12601  *  is very slow because it runs through the conversion data in a linear
12602  *  fashion to save space (which is why ASCII characters have a special
12603  *  fast path before arriving here).
12604  *
12605  *  The particular bit counts etc have been determined experimentally to
12606  *  be small but still sufficient, and must match the Python script
12607  *  (tools/extract_caseconv.py).
12608  *
12609  *  The return value is the case converted codepoint or -1 if the conversion
12610  *  results in multiple characters (this is useful for regexp Canonicalization
12611  *  operation).  If 'buf' is not NULL, the result codepoint(s) are also
12612  *  appended to the hbuffer.
12613  *
12614  *  Context and locale specific rules must be checked before consulting
12615  *  this function.
12616  */
12617
12618 DUK_LOCAL
12619 duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
12620                                           duk_bufwriter_ctx *bw,
12621                                           duk_codepoint_t cp,
12622                                           duk_bitdecoder_ctx *bd_ctx) {
12623         duk_small_int_t skip = 0;
12624         duk_small_int_t n;
12625         duk_small_int_t t;
12626         duk_small_int_t count;
12627         duk_codepoint_t tmp_cp;
12628         duk_codepoint_t start_i;
12629         duk_codepoint_t start_o;
12630
12631         DUK_ASSERT(bd_ctx != NULL);
12632         DUK_UNREF(thr);
12633
12634         DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
12635
12636         /* range conversion with a "skip" */
12637         DUK_DDD(DUK_DDDPRINT("checking ranges"));
12638         for (;;) {
12639                 skip++;
12640                 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
12641                 if (n == 0x3f) {
12642                         /* end marker */
12643                         break;
12644                 }
12645                 DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld", (long) skip, (long) n));
12646
12647                 while (n--) {
12648                         start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12649                         start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12650                         count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
12651                         DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld",
12652                                              (long) start_i, (long) start_o, (long) count, (long) skip));
12653
12654                         if (cp >= start_i) {
12655                                 tmp_cp = cp - start_i;  /* always >= 0 */
12656                                 if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip &&
12657                                     (tmp_cp % (duk_codepoint_t) skip) == 0) {
12658                                         DUK_DDD(DUK_DDDPRINT("range matches input codepoint"));
12659                                         cp = start_o + tmp_cp;
12660                                         goto single;
12661                                 }
12662                         }
12663                 }
12664         }
12665
12666         /* 1:1 conversion */
12667         n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
12668         DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n));
12669         while (n--) {
12670                 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12671                 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12672                 DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld", (long) start_i, (long) start_o));
12673                 if (cp == start_i) {
12674                         DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint"));
12675                         cp = start_o;
12676                         goto single;
12677                 }
12678         }
12679
12680         /* complex, multicharacter conversion */
12681         n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
12682         DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)", (long) n));
12683         while (n--) {
12684                 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12685                 t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2);
12686                 DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars", (long) start_i, (long) t));
12687                 if (cp == start_i) {
12688                         DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint"));
12689                         if (bw != NULL) {
12690                                 while (t--) {
12691                                         tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
12692                                         DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp);
12693                                 }
12694                         }
12695                         return -1;
12696                 } else {
12697                         while (t--) {
12698                                 (void) duk_bd_decode(bd_ctx, 16);
12699                         }
12700                 }
12701         }
12702
12703         /* default: no change */
12704         DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input"));
12705         /* fall through */
12706
12707  single:
12708         if (bw != NULL) {
12709                 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
12710         }
12711         return cp;
12712 }
12713
12714 /*
12715  *  Case conversion helper, with context/local sensitivity.
12716  *  For proper case conversion, one needs to know the character
12717  *  and the preceding and following characters, as well as
12718  *  locale/language.
12719  */
12720
12721 /* XXX: add 'language' argument when locale/language sensitive rule
12722  * support added.
12723  */
12724 DUK_LOCAL
12725 duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
12726                                            duk_bufwriter_ctx *bw,
12727                                            duk_codepoint_t cp,
12728                                            duk_codepoint_t prev,
12729                                            duk_codepoint_t next,
12730                                            duk_bool_t uppercase) {
12731         duk_bitdecoder_ctx bd_ctx;
12732
12733         /* fast path for ASCII */
12734         if (cp < 0x80L) {
12735                 /* XXX: there are language sensitive rules for the ASCII range.
12736                  * If/when language/locale support is implemented, they need to
12737                  * be implemented here for the fast path.  There are no context
12738                  * sensitive rules for ASCII range.
12739                  */
12740
12741                 if (uppercase) {
12742                         if (cp >= 'a' && cp <= 'z') {
12743                                 cp = cp - 'a' + 'A';
12744                         }
12745                 } else {
12746                         if (cp >= 'A' && cp <= 'Z') {
12747                                 cp = cp - 'A' + 'a';
12748                         }
12749                 }
12750
12751                 if (bw != NULL) {
12752                         DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp);
12753                 }
12754                 return cp;
12755         }
12756
12757         /* context and locale specific rules which cannot currently be represented
12758          * in the caseconv bitstream: hardcoded rules in C
12759          */
12760         if (uppercase) {
12761                 /* XXX: turkish / azeri */
12762         } else {
12763                 /*
12764                  *  Final sigma context specific rule.  This is a rather tricky
12765                  *  rule and this handling is probably not 100% correct now.
12766                  *  The rule is not locale/language specific so it is supported.
12767                  */
12768
12769                 if (cp == 0x03a3L &&    /* U+03A3 = GREEK CAPITAL LETTER SIGMA */
12770                     duk_unicode_is_letter(prev) &&        /* prev exists and is not a letter */
12771                     !duk_unicode_is_letter(next)) {       /* next does not exist or next is not a letter */
12772                         /* Capital sigma occurred at "end of word", lowercase to
12773                          * U+03C2 = GREEK SMALL LETTER FINAL SIGMA.  Otherwise
12774                          * fall through and let the normal rules lowercase it to
12775                          * U+03C3 = GREEK SMALL LETTER SIGMA.
12776                          */
12777                         cp = 0x03c2L;
12778                         goto singlechar;
12779                 }
12780
12781                 /* XXX: lithuanian not implemented */
12782                 /* XXX: lithuanian, explicit dot rules */
12783                 /* XXX: turkish / azeri, lowercase rules */
12784         }
12785
12786         /* 1:1 or special conversions, but not locale/context specific: script generated rules */
12787         duk_memzero(&bd_ctx, sizeof(bd_ctx));
12788         if (uppercase) {
12789                 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc;
12790                 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
12791         } else {
12792                 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc;
12793                 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc);
12794         }
12795         return duk__slow_case_conversion(thr, bw, cp, &bd_ctx);
12796
12797  singlechar:
12798         if (bw != NULL) {
12799                 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
12800         }
12801         return cp;
12802
12803  /* unused now, not needed until Turkish/Azeri */
12804 #if 0
12805  nochar:
12806         return -1;
12807 #endif
12808 }
12809
12810 /*
12811  *  Replace valstack top with case converted version.
12812  */
12813
12814 DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase) {
12815         duk_hstring *h_input;
12816         duk_bufwriter_ctx bw_alloc;
12817         duk_bufwriter_ctx *bw;
12818         const duk_uint8_t *p, *p_start, *p_end;
12819         duk_codepoint_t prev, curr, next;
12820
12821         h_input = duk_require_hstring(thr, -1);  /* Accept symbols. */
12822         DUK_ASSERT(h_input != NULL);
12823
12824         bw = &bw_alloc;
12825         DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));
12826
12827         /* [ ... input buffer ] */
12828
12829         p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
12830         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
12831         p = p_start;
12832
12833         prev = -1; DUK_UNREF(prev);
12834         curr = -1;
12835         next = -1;
12836         for (;;) {
12837                 prev = curr;
12838                 curr = next;
12839                 next = -1;
12840                 if (p < p_end) {
12841                         next = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
12842                 } else {
12843                         /* end of input and last char has been processed */
12844                         if (curr < 0) {
12845                                 break;
12846                         }
12847                 }
12848
12849                 /* on first round, skip */
12850                 if (curr >= 0) {
12851                         /* XXX: could add a fast path to process chunks of input codepoints,
12852                          * but relative benefit would be quite small.
12853                          */
12854
12855                         /* Ensure space for maximum multi-character result; estimate is overkill. */
12856                         DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH);
12857
12858                         duk__case_transform_helper(thr,
12859                                                    bw,
12860                                                    (duk_codepoint_t) curr,
12861                                                    prev,
12862                                                    next,
12863                                                    uppercase);
12864                 }
12865         }
12866
12867         DUK_BW_COMPACT(thr, bw);
12868         (void) duk_buffer_to_string(thr, -1);  /* Safe, output is encoded. */
12869         /* invalidates h_buf pointer */
12870         duk_remove_m2(thr);
12871 }
12872
12873 #if defined(DUK_USE_REGEXP_SUPPORT)
12874
12875 /*
12876  *  Canonicalize() abstract operation needed for canonicalization of individual
12877  *  codepoints during regexp compilation and execution, see E5 Section 15.10.2.8.
12878  *  Note that codepoints are canonicalized one character at a time, so no context
12879  *  specific rules can apply.  Locale specific rules can apply, though.
12880  */
12881
12882 DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) {
12883 #if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
12884         /* Fast canonicalization lookup at the cost of 128kB footprint. */
12885         DUK_ASSERT(cp >= 0);
12886         DUK_UNREF(thr);
12887         if (DUK_LIKELY(cp < 0x10000L)) {
12888                 return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp];
12889         }
12890         return cp;
12891 #else  /* DUK_USE_REGEXP_CANON_WORKAROUND */
12892         duk_codepoint_t y;
12893
12894         y = duk__case_transform_helper(thr,
12895                                        NULL,    /* NULL is allowed, no output */
12896                                        cp,      /* curr char */
12897                                        -1,      /* prev char */
12898                                        -1,      /* next char */
12899                                        1);      /* uppercase */
12900
12901         if ((y < 0) || (cp >= 0x80 && y < 0x80)) {
12902                 /* multiple codepoint conversion or non-ASCII mapped to ASCII
12903                  * --> leave as is.
12904                  */
12905                 return cp;
12906         }
12907
12908         return y;
12909 #endif  /* DUK_USE_REGEXP_CANON_WORKAROUND */
12910 }
12911
12912 /*
12913  *  E5 Section 15.10.2.6 "IsWordChar" abstract operation.  Assume
12914  *  x < 0 for characters read outside the string.
12915  */
12916
12917 DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) {
12918         /*
12919          *  Note: the description in E5 Section 15.10.2.6 has a typo, it
12920          *  contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_].
12921          */
12922         if ((x >= '0' && x <= '9') ||
12923             (x >= 'a' && x <= 'z') ||
12924             (x >= 'A' && x <= 'Z') ||
12925             (x == '_')) {
12926                 return 1;
12927         }
12928         return 0;
12929 }
12930
12931 /*
12932  *  Regexp range tables
12933  */
12934
12935 /* exposed because lexer needs these too */
12936 DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = {
12937         (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
12938 };
12939 DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = {
12940         (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL,
12941         (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL,
12942         (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL,
12943         (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL,
12944         (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL,
12945         (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL,
12946         (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL,
12947         (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL,
12948         (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL,
12949         (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL,
12950         (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL,
12951 };
12952 DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = {
12953         (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
12954         (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL,
12955         (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL,
12956         (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL,
12957 };
12958 DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = {
12959         (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
12960         (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL,
12961 };
12962 DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = {
12963         (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL,
12964         (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL,
12965         (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL,
12966         (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL,
12967         (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL,
12968         (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL,
12969         (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL,
12970         (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL,
12971         (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL,
12972         (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL,
12973         (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL,
12974         (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL,
12975 };
12976 DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
12977         (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
12978         (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL,
12979         (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL,
12980         (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL,
12981         (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL,
12982 };
12983
12984 #endif  /* DUK_USE_REGEXP_SUPPORT */
12985 #line 1 "duk_util_misc.c"
12986 /*
12987  *  Misc util stuff.
12988  */
12989
12990 /* #include duk_internal.h -> already included */
12991
12992 /*
12993  *  Lowercase digits for radix values 2 to 36.  Also doubles as lowercase
12994  *  hex nybble table.
12995  */
12996
12997 DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = {
12998         DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
12999         DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
13000         DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B,
13001         DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F,
13002         DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J,
13003         DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N,
13004         DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R,
13005         DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V,
13006         DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z
13007 };
13008
13009 DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = {
13010         DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
13011         DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
13012         DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B,
13013         DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F
13014 };
13015
13016 /*
13017  *  Table for hex decoding ASCII hex digits
13018  */
13019
13020 DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = {
13021         /* -1 if invalid */
13022         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x00-0x0f */
13023         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x10-0x1f */
13024         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x20-0x2f */
13025          0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,  /* 0x30-0x3f */
13026         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x40-0x4f */
13027         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x50-0x5f */
13028         -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x60-0x6f */
13029         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x70-0x7f */
13030         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x80-0x8f */
13031         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0x90-0x9f */
13032         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0xa0-0xaf */
13033         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0xb0-0xbf */
13034         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0xc0-0xcf */
13035         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0xd0-0xdf */
13036         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  /* 0xe0-0xef */
13037         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1   /* 0xf0-0xff */
13038 };
13039
13040 #if defined(DUK_USE_HEX_FASTPATH)
13041 /* Preshifted << 4.  Must use 16-bit entry to allow negative value signaling. */
13042 DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = {
13043           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x00-0x0f */
13044           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x10-0x1f */
13045           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x20-0x2f */
13046         0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x30-0x3f */
13047           -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x40-0x4f */
13048           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x50-0x5f */
13049           -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x60-0x6f */
13050           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x70-0x7f */
13051           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x80-0x8f */
13052           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0x90-0x9f */
13053           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0xa0-0xaf */
13054           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0xb0-0xbf */
13055           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0xc0-0xcf */
13056           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0xd0-0xdf */
13057           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  /* 0xe0-0xef */
13058           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1   /* 0xf0-0xff */
13059 };
13060 #endif
13061
13062 /*
13063  *  Table for hex encoding bytes
13064  */
13065
13066 #if defined(DUK_USE_HEX_FASTPATH)
13067 /* Lookup to encode one byte directly into 2 characters:
13068  *
13069  *   def genhextab(bswap):
13070  *       for i in xrange(256):
13071  *           t = chr(i).encode('hex')
13072  *           if bswap:
13073  *               t = t[1] + t[0]
13074  *           print('0x' + t.encode('hex') + 'U')
13075  *   print('big endian'); genhextab(False)
13076  *   print('little endian'); genhextab(True)
13077 */
13078 DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = {
13079 #if defined(DUK_USE_INTEGER_BE)
13080         0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U,
13081         0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U,
13082         0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U,
13083         0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U,
13084         0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U,
13085         0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U,
13086         0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U,
13087         0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U,
13088         0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U,
13089         0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U,
13090         0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U,
13091         0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U,
13092         0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U,
13093         0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U,
13094         0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U,
13095         0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U,
13096         0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U,
13097         0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U,
13098         0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U,
13099         0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U,
13100         0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U,
13101         0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U,
13102         0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U,
13103         0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U,
13104         0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U,
13105         0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U,
13106         0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U,
13107         0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U,
13108         0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U,
13109         0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U,
13110         0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U,
13111         0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U
13112 #else  /* DUK_USE_INTEGER_BE */
13113         0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U,
13114         0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U,
13115         0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U,
13116         0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U,
13117         0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U,
13118         0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U,
13119         0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U,
13120         0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U,
13121         0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U,
13122         0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U,
13123         0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U,
13124         0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U,
13125         0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U,
13126         0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U,
13127         0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U,
13128         0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U,
13129         0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U,
13130         0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U,
13131         0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U,
13132         0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U,
13133         0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U,
13134         0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U,
13135         0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U,
13136         0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U,
13137         0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U,
13138         0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U,
13139         0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U,
13140         0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U,
13141         0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U,
13142         0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U,
13143         0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U,
13144         0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U
13145 #endif  /* DUK_USE_INTEGER_BE */
13146 };
13147 #endif  /* DUK_USE_HEX_FASTPATH */
13148
13149 /*
13150  *  Arbitrary byteswap for potentially unaligned values
13151  *
13152  *  Used to byteswap pointers e.g. in debugger code.
13153  */
13154
13155 #if defined(DUK_USE_DEBUGGER_SUPPORT)  /* For now only needed by the debugger. */
13156 DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
13157         duk_uint8_t tmp;
13158         duk_uint8_t *q = p + len - 1;
13159
13160         while (p - q < 0) {
13161                 tmp = *p;
13162                 *p = *q;
13163                 *q = tmp;
13164                 p++;
13165                 q--;
13166         }
13167 }
13168 #endif
13169 #line 1 "duk_hobject_class.c"
13170 /*
13171  *  Hobject ECMAScript [[Class]].
13172  */
13173
13174 /* #include duk_internal.h -> already included */
13175
13176 #if (DUK_STRIDX_UC_ARGUMENTS > 255)
13177 #error constant too large
13178 #endif
13179 #if (DUK_STRIDX_ARRAY > 255)
13180 #error constant too large
13181 #endif
13182 #if (DUK_STRIDX_UC_BOOLEAN > 255)
13183 #error constant too large
13184 #endif
13185 #if (DUK_STRIDX_DATE > 255)
13186 #error constant too large
13187 #endif
13188 #if (DUK_STRIDX_UC_ERROR > 255)
13189 #error constant too large
13190 #endif
13191 #if (DUK_STRIDX_UC_FUNCTION > 255)
13192 #error constant too large
13193 #endif
13194 #if (DUK_STRIDX_JSON > 255)
13195 #error constant too large
13196 #endif
13197 #if (DUK_STRIDX_MATH > 255)
13198 #error constant too large
13199 #endif
13200 #if (DUK_STRIDX_UC_NUMBER > 255)
13201 #error constant too large
13202 #endif
13203 #if (DUK_STRIDX_UC_OBJECT > 255)
13204 #error constant too large
13205 #endif
13206 #if (DUK_STRIDX_REG_EXP > 255)
13207 #error constant too large
13208 #endif
13209 #if (DUK_STRIDX_UC_STRING > 255)
13210 #error constant too large
13211 #endif
13212 #if (DUK_STRIDX_GLOBAL > 255)
13213 #error constant too large
13214 #endif
13215 #if (DUK_STRIDX_OBJ_ENV > 255)
13216 #error constant too large
13217 #endif
13218 #if (DUK_STRIDX_DEC_ENV > 255)
13219 #error constant too large
13220 #endif
13221 #if (DUK_STRIDX_UC_POINTER > 255)
13222 #error constant too large
13223 #endif
13224 #if (DUK_STRIDX_UC_THREAD > 255)
13225 #error constant too large
13226 #endif
13227 #if (DUK_STRIDX_ARRAY_BUFFER > 255)
13228 #error constant too large
13229 #endif
13230 #if (DUK_STRIDX_DATA_VIEW > 255)
13231 #error constant too large
13232 #endif
13233 #if (DUK_STRIDX_INT8_ARRAY > 255)
13234 #error constant too large
13235 #endif
13236 #if (DUK_STRIDX_UINT8_ARRAY > 255)
13237 #error constant too large
13238 #endif
13239 #if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255)
13240 #error constant too large
13241 #endif
13242 #if (DUK_STRIDX_INT16_ARRAY > 255)
13243 #error constant too large
13244 #endif
13245 #if (DUK_STRIDX_UINT16_ARRAY > 255)
13246 #error constant too large
13247 #endif
13248 #if (DUK_STRIDX_INT32_ARRAY > 255)
13249 #error constant too large
13250 #endif
13251 #if (DUK_STRIDX_UINT32_ARRAY > 255)
13252 #error constant too large
13253 #endif
13254 #if (DUK_STRIDX_FLOAT32_ARRAY > 255)
13255 #error constant too large
13256 #endif
13257 #if (DUK_STRIDX_FLOAT64_ARRAY > 255)
13258 #error constant too large
13259 #endif
13260 #if (DUK_STRIDX_EMPTY_STRING > 255)
13261 #error constant too large
13262 #endif
13263
13264 /* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
13265 DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
13266         DUK_STRIDX_EMPTY_STRING,  /* NONE, intentionally empty */
13267         DUK_STRIDX_UC_OBJECT,
13268         DUK_STRIDX_ARRAY,
13269         DUK_STRIDX_UC_FUNCTION,
13270         DUK_STRIDX_UC_ARGUMENTS,
13271         DUK_STRIDX_UC_BOOLEAN,
13272         DUK_STRIDX_DATE,
13273         DUK_STRIDX_UC_ERROR,
13274         DUK_STRIDX_JSON,
13275         DUK_STRIDX_MATH,
13276         DUK_STRIDX_UC_NUMBER,
13277         DUK_STRIDX_REG_EXP,
13278         DUK_STRIDX_UC_STRING,
13279         DUK_STRIDX_GLOBAL,
13280         DUK_STRIDX_UC_SYMBOL,
13281         DUK_STRIDX_OBJ_ENV,
13282         DUK_STRIDX_DEC_ENV,
13283         DUK_STRIDX_UC_POINTER,
13284         DUK_STRIDX_UC_THREAD,
13285         DUK_STRIDX_ARRAY_BUFFER,
13286         DUK_STRIDX_DATA_VIEW,
13287         DUK_STRIDX_INT8_ARRAY,
13288         DUK_STRIDX_UINT8_ARRAY,
13289         DUK_STRIDX_UINT8_CLAMPED_ARRAY,
13290         DUK_STRIDX_INT16_ARRAY,
13291         DUK_STRIDX_UINT16_ARRAY,
13292         DUK_STRIDX_INT32_ARRAY,
13293         DUK_STRIDX_UINT32_ARRAY,
13294         DUK_STRIDX_FLOAT32_ARRAY,
13295         DUK_STRIDX_FLOAT64_ARRAY,
13296         DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
13297         DUK_STRIDX_EMPTY_STRING,  /* UNUSED, intentionally empty */
13298 };
13299 #line 1 "duk_alloc_default.c"
13300 /*
13301  *  Default allocation functions.
13302  *
13303  *  Assumes behavior such as malloc allowing zero size, yielding
13304  *  a NULL or a unique pointer which is a no-op for free.
13305  */
13306
13307 /* #include duk_internal.h -> already included */
13308
13309 #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
13310 DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
13311         void *res;
13312         DUK_UNREF(udata);
13313         res = DUK_ANSI_MALLOC(size);
13314         DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p",
13315                              (unsigned long) size, (void *) res));
13316         return res;
13317 }
13318
13319 DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) {
13320         void *res;
13321         DUK_UNREF(udata);
13322         res = DUK_ANSI_REALLOC(ptr, newsize);
13323         DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p",
13324                              (void *) ptr, (unsigned long) newsize, (void *) res));
13325         return res;
13326 }
13327
13328 DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
13329         DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr));
13330         DUK_UNREF(udata);
13331         DUK_ANSI_FREE(ptr);
13332 }
13333 #endif  /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */
13334 #line 1 "duk_api_buffer.c"
13335 /*
13336  *  Buffer
13337  */
13338
13339 /* #include duk_internal.h -> already included */
13340
13341 DUK_EXTERNAL void *duk_resize_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t new_size) {
13342         duk_hbuffer_dynamic *h;
13343
13344         DUK_ASSERT_API_ENTRY(thr);
13345
13346         h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
13347         DUK_ASSERT(h != NULL);
13348
13349         if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
13350                 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
13351                 DUK_WO_NORETURN(return NULL;);
13352         }
13353
13354         /* Maximum size check is handled by callee. */
13355         duk_hbuffer_resize(thr, h, new_size);
13356
13357         return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
13358 }
13359
13360 DUK_EXTERNAL void *duk_steal_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
13361         duk_hbuffer_dynamic *h;
13362         void *ptr;
13363         duk_size_t sz;
13364
13365         DUK_ASSERT_API_ENTRY(thr);
13366
13367         h = (duk_hbuffer_dynamic *) duk_require_hbuffer(thr, idx);
13368         DUK_ASSERT(h != NULL);
13369
13370         if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
13371                 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
13372                 DUK_WO_NORETURN(return NULL;);
13373         }
13374
13375         /* Forget the previous allocation, setting size to 0 and alloc to
13376          * NULL.  Caller is responsible for freeing the previous allocation.
13377          * Getting the allocation and clearing it is done in the same API
13378          * call to avoid any chance of a realloc.
13379          */
13380         ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
13381         sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h);
13382         if (out_size) {
13383                 *out_size = sz;
13384         }
13385         DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h);
13386         DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0);
13387
13388         return ptr;
13389 }
13390
13391 DUK_EXTERNAL void duk_config_buffer(duk_hthread *thr, duk_idx_t idx, void *ptr, duk_size_t len) {
13392         duk_hbuffer_external *h;
13393
13394         DUK_ASSERT_API_ENTRY(thr);
13395
13396         h = (duk_hbuffer_external *) duk_require_hbuffer(thr, idx);
13397         DUK_ASSERT(h != NULL);
13398
13399         if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
13400                 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
13401                 DUK_WO_NORETURN(return;);
13402         }
13403         DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
13404
13405         DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr);
13406         DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len);
13407 }
13408 #line 1 "duk_api_bytecode.c"
13409 /*
13410  *  Bytecode dump/load
13411  *
13412  *  The bytecode load primitive is more important performance-wise than the
13413  *  dump primitive.
13414  *
13415  *  Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be
13416  *  memory safe for invalid arguments - caller beware!  There's little point
13417  *  in trying to achieve memory safety unless bytecode instructions are also
13418  *  validated which is not easy to do with indirect register references etc.
13419  */
13420
13421 /* #include duk_internal.h -> already included */
13422
13423 #if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
13424
13425 #define DUK__SER_MARKER  0xbf
13426 #define DUK__SER_STRING  0x00
13427 #define DUK__SER_NUMBER  0x01
13428 #define DUK__BYTECODE_INITIAL_ALLOC 256
13429 #define DUK__NO_FORMALS  0xffffffffUL
13430
13431 /*
13432  *  Dump/load helpers, xxx_raw() helpers do no buffer checks
13433  */
13434
13435 DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_hthread *thr, duk_uint8_t *p) {
13436         duk_uint32_t len;
13437
13438         len = DUK_RAW_READ_U32_BE(p);
13439         duk_push_lstring(thr, (const char *) p, len);
13440         p += len;
13441         return p;
13442 }
13443
13444 DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_hthread *thr, duk_uint8_t *p) {
13445         duk_uint32_t len;
13446         duk_uint8_t *buf;
13447
13448         len = DUK_RAW_READ_U32_BE(p);
13449         buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len);
13450         DUK_ASSERT(buf != NULL);
13451         duk_memcpy((void *) buf, (const void *) p, (size_t) len);
13452         p += len;
13453         return p;
13454 }
13455
13456 DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) {
13457         duk_size_t len;
13458         duk_uint32_t tmp32;
13459
13460         DUK_ASSERT(h != NULL);
13461
13462         len = DUK_HSTRING_GET_BYTELEN(h);
13463         DUK_ASSERT(len <= 0xffffffffUL);  /* string limits */
13464         tmp32 = (duk_uint32_t) len;
13465         DUK_RAW_WRITE_U32_BE(p, tmp32);
13466         duk_memcpy((void *) p,
13467                    (const void *) DUK_HSTRING_GET_DATA(h),
13468                    len);
13469         p += len;
13470         return p;
13471 }
13472
13473 DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) {
13474         duk_size_t len;
13475         duk_uint32_t tmp32;
13476
13477         DUK_ASSERT(thr != NULL);
13478         DUK_ASSERT(h != NULL);
13479         DUK_UNREF(thr);
13480
13481         len = DUK_HBUFFER_GET_SIZE(h);
13482         DUK_ASSERT(len <= 0xffffffffUL);  /* buffer limits */
13483         tmp32 = (duk_uint32_t) len;
13484         DUK_RAW_WRITE_U32_BE(p, tmp32);
13485         /* When len == 0, buffer data pointer may be NULL. */
13486         duk_memcpy_unsafe((void *) p,
13487                           (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
13488                           len);
13489         p += len;
13490         return p;
13491 }
13492
13493 DUK_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) {
13494         duk_hstring *h_str;
13495         duk_tval *tv;
13496
13497         tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
13498         if (tv != NULL && DUK_TVAL_IS_STRING(tv)) {
13499                 h_str = DUK_TVAL_GET_STRING(tv);
13500                 DUK_ASSERT(h_str != NULL);
13501         } else {
13502                 h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
13503                 DUK_ASSERT(h_str != NULL);
13504         }
13505         DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL);  /* ensures no overflow */
13506         p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
13507         p = duk__dump_hstring_raw(p, h_str);
13508         return p;
13509 }
13510
13511 DUK_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) {
13512         duk_tval *tv;
13513
13514         tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
13515         if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) {
13516                 duk_hbuffer *h_buf;
13517                 h_buf = DUK_TVAL_GET_BUFFER(tv);
13518                 DUK_ASSERT(h_buf != NULL);
13519                 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL);  /* ensures no overflow */
13520                 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HBUFFER_GET_SIZE(h_buf), p);
13521                 p = duk__dump_hbuffer_raw(thr, p, h_buf);
13522         } else {
13523                 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13524                 DUK_RAW_WRITE_U32_BE(p, 0);
13525         }
13526         return p;
13527 }
13528
13529 DUK_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) {
13530         duk_tval *tv;
13531         duk_uint32_t val;
13532
13533         tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
13534         if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) {
13535                 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
13536         } else {
13537                 val = def_value;
13538         }
13539         p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13540         DUK_RAW_WRITE_U32_BE(p, val);
13541         return p;
13542 }
13543
13544 DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
13545         duk_tval *tv;
13546
13547         tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
13548         if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
13549                 duk_hobject *h;
13550                 duk_uint_fast32_t i;
13551
13552                 h = DUK_TVAL_GET_OBJECT(tv);
13553                 DUK_ASSERT(h != NULL);
13554
13555                 /* We know _Varmap only has own properties so walk property
13556                  * table directly.  We also know _Varmap is dense and all
13557                  * values are numbers; assert for these.  GC and finalizers
13558                  * shouldn't affect _Varmap so side effects should be fine.
13559                  */
13560                 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
13561                         duk_hstring *key;
13562                         duk_tval *tv_val;
13563                         duk_uint32_t val;
13564
13565                         key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
13566                         DUK_ASSERT(key != NULL);  /* _Varmap is dense */
13567                         DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i));
13568                         tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i);
13569                         DUK_ASSERT(tv_val != NULL);
13570                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val));  /* known to be number; in fact an integer */
13571 #if defined(DUK_USE_FASTINT)
13572                         DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val));
13573                         DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val));  /* known to be 32-bit */
13574                         val = DUK_TVAL_GET_FASTINT_U32(tv_val);
13575 #else
13576                         val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val);
13577 #endif
13578
13579                         DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL);  /* ensures no overflow */
13580                         p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(key) + 4U, p);
13581                         p = duk__dump_hstring_raw(p, key);
13582                         DUK_RAW_WRITE_U32_BE(p, val);
13583                 }
13584         }
13585         p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13586         DUK_RAW_WRITE_U32_BE(p, 0);  /* end of _Varmap */
13587         return p;
13588 }
13589
13590 DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
13591         duk_tval *tv;
13592
13593         tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
13594         if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
13595                 duk_harray *h;
13596                 duk_uint32_t i;
13597
13598                 /* Here we rely on _Formals being a dense array containing
13599                  * strings.  This should be the case unless _Formals has been
13600                  * tweaked by the application (which we don't support right
13601                  * now).
13602                  */
13603                 h = (duk_harray *) DUK_TVAL_GET_OBJECT(tv);
13604                 DUK_ASSERT(h != NULL);
13605                 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
13606                 DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h));
13607
13608                 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13609                 DUK_ASSERT(h->length != DUK__NO_FORMALS);  /* limits */
13610                 DUK_RAW_WRITE_U32_BE(p, h->length);
13611
13612                 for (i = 0; i < h->length; i++) {
13613                         duk_tval *tv_val;
13614                         duk_hstring *varname;
13615
13616                         tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i);
13617                         DUK_ASSERT(tv_val != NULL);
13618                         DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val));
13619
13620                         varname = DUK_TVAL_GET_STRING(tv_val);
13621                         DUK_ASSERT(varname != NULL);
13622                         DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1);
13623
13624                         DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL);  /* ensures no overflow */
13625                         p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U + DUK_HSTRING_GET_BYTELEN(varname), p);
13626                         p = duk__dump_hstring_raw(p, varname);
13627                 }
13628         } else {
13629                 DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals"));
13630                 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4U, p);
13631                 DUK_RAW_WRITE_U32_BE(p, DUK__NO_FORMALS);  /* marker: no formals */
13632         }
13633         return p;
13634 }
13635
13636 static duk_uint8_t *duk__dump_func(duk_hthread *thr, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
13637         duk_tval *tv, *tv_end;
13638         duk_instr_t *ins, *ins_end;
13639         duk_hobject **fn, **fn_end;
13640         duk_hstring *h_str;
13641         duk_uint32_t count_instr;
13642         duk_uint32_t tmp32;
13643         duk_uint16_t tmp16;
13644         duk_double_t d;
13645
13646         DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
13647                            "consts=[%p,%p[ (%ld bytes, %ld items), "
13648                            "funcs=[%p,%p[ (%ld bytes, %ld items), "
13649                            "code=[%p,%p[ (%ld bytes, %ld items)",
13650                            (void *) func,
13651                            (void *) p,
13652                            (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func),
13653                            (void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func),
13654                            (long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func),
13655                            (long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func),
13656                            (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func),
13657                            (void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func),
13658                            (long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func),
13659                            (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func),
13660                            (void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func),
13661                            (void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func),
13662                            (long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func),
13663                            (long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func)));
13664
13665         DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL);  /* ensures no overflow */
13666         count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func);
13667         p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3U * 4U + 2U * 2U + 3U * 4U + count_instr * 4U, p);
13668
13669         /* Fixed header info. */
13670         tmp32 = count_instr;
13671         DUK_RAW_WRITE_U32_BE(p, tmp32);
13672         tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func);
13673         DUK_RAW_WRITE_U32_BE(p, tmp32);
13674         tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func);
13675         DUK_RAW_WRITE_U32_BE(p, tmp32);
13676         tmp16 = func->nregs;
13677         DUK_RAW_WRITE_U16_BE(p, tmp16);
13678         tmp16 = func->nargs;
13679         DUK_RAW_WRITE_U16_BE(p, tmp16);
13680 #if defined(DUK_USE_DEBUGGER_SUPPORT)
13681         tmp32 = func->start_line;
13682         DUK_RAW_WRITE_U32_BE(p, tmp32);
13683         tmp32 = func->end_line;
13684         DUK_RAW_WRITE_U32_BE(p, tmp32);
13685 #else
13686         DUK_RAW_WRITE_U32_BE(p, 0);
13687         DUK_RAW_WRITE_U32_BE(p, 0);
13688 #endif
13689         tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func);  /* masks flags, only duk_hobject flags */
13690         tmp32 &= ~(DUK_HOBJECT_FLAG_HAVE_FINALIZER);  /* finalizer flag is lost */
13691         DUK_RAW_WRITE_U32_BE(p, tmp32);
13692
13693         /* Bytecode instructions: endian conversion needed unless
13694          * platform is big endian.
13695          */
13696         ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func);
13697         ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func);
13698         DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
13699 #if defined(DUK_USE_INTEGER_BE)
13700         duk_memcpy_unsafe((void *) p, (const void *) ins, (size_t) (ins_end - ins));
13701         p += (size_t) (ins_end - ins);
13702 #else
13703         while (ins != ins_end) {
13704                 tmp32 = (duk_uint32_t) (*ins);
13705                 DUK_RAW_WRITE_U32_BE(p, tmp32);
13706                 ins++;
13707         }
13708 #endif
13709
13710         /* Constants: variable size encoding. */
13711         tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func);
13712         tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func);
13713         while (tv != tv_end) {
13714                 /* constants are strings or numbers now */
13715                 DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
13716                            DUK_TVAL_IS_NUMBER(tv));
13717
13718                 if (DUK_TVAL_IS_STRING(tv)) {
13719                         h_str = DUK_TVAL_GET_STRING(tv);
13720                         DUK_ASSERT(h_str != NULL);
13721                         DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL);  /* ensures no overflow */
13722                         p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 4U + DUK_HSTRING_GET_BYTELEN(h_str), p);
13723                         *p++ = DUK__SER_STRING;
13724                         p = duk__dump_hstring_raw(p, h_str);
13725                 } else {
13726                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
13727                         p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1U + 8U, p);
13728                         *p++ = DUK__SER_NUMBER;
13729                         d = DUK_TVAL_GET_NUMBER(tv);
13730                         DUK_RAW_WRITE_DOUBLE_BE(p, d);
13731                 }
13732                 tv++;
13733         }
13734
13735         /* Inner functions recursively. */
13736         fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func);
13737         fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func);
13738         while (fn != fn_end) {
13739                 /* XXX: This causes recursion up to inner function depth
13740                  * which is normally not an issue, e.g. mark-and-sweep uses
13741                  * a recursion limiter to avoid C stack issues.  Avoiding
13742                  * this would mean some sort of a work list or just refusing
13743                  * to serialize deep functions.
13744                  */
13745                 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn));
13746                 p = duk__dump_func(thr, (duk_hcompfunc *) *fn, bw_ctx, p);
13747                 fn++;
13748         }
13749
13750         /* Lexenv and varenv are not dumped. */
13751
13752         /* Object extra properties.
13753          *
13754          * There are some difference between function templates and functions.
13755          * For example, function templates don't have .length and nargs is
13756          * normally used to instantiate the functions.
13757          */
13758
13759         p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
13760 #if defined(DUK_USE_FUNC_NAME_PROPERTY)
13761         p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
13762 #endif
13763 #if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
13764         p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
13765 #endif
13766 #if defined(DUK_USE_PC2LINE)
13767         p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
13768 #endif
13769         p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
13770         p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
13771
13772         DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p));
13773
13774         return p;
13775 }
13776
13777 /* Load a function from bytecode.  The function object returned here must
13778  * match what is created by duk_js_push_closure() with respect to its flags,
13779  * properties, etc.
13780  *
13781  * NOTE: there are intentionally no input buffer length / bound checks.
13782  * Adding them would be easy but wouldn't ensure memory safety as untrusted
13783  * or broken bytecode is unsafe during execution unless the opcodes themselves
13784  * are validated (which is quite complex, especially for indirect opcodes).
13785  */
13786
13787 #define DUK__ASSERT_LEFT(n) do { \
13788                 DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
13789         } while (0)
13790
13791 static duk_uint8_t *duk__load_func(duk_hthread *thr, duk_uint8_t *p, duk_uint8_t *p_end) {
13792         duk_hcompfunc *h_fun;
13793         duk_hbuffer *h_data;
13794         duk_size_t data_size;
13795         duk_uint32_t count_instr, count_const, count_funcs;
13796         duk_uint32_t n;
13797         duk_uint32_t tmp32;
13798         duk_small_uint_t const_type;
13799         duk_uint8_t *fun_data;
13800         duk_uint8_t *q;
13801         duk_idx_t idx_base;
13802         duk_tval *tv1;
13803         duk_uarridx_t arr_idx;
13804         duk_uarridx_t arr_limit;
13805         duk_hobject *func_env;
13806         duk_bool_t need_pop;
13807
13808         /* XXX: There's some overlap with duk_js_closure() here, but
13809          * seems difficult to share code.  Ensure that the final function
13810          * looks the same as created by duk_js_closure().
13811          */
13812
13813         DUK_ASSERT(thr != NULL);
13814
13815         DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
13816
13817         DUK__ASSERT_LEFT(3 * 4);
13818         count_instr = DUK_RAW_READ_U32_BE(p);
13819         count_const = DUK_RAW_READ_U32_BE(p);
13820         count_funcs = DUK_RAW_READ_U32_BE(p);
13821
13822         data_size = sizeof(duk_tval) * count_const +
13823                     sizeof(duk_hobject *) * count_funcs +
13824                     sizeof(duk_instr_t) * count_instr;
13825
13826         DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld",
13827                            (long) count_instr, (long) count_const,
13828                            (long) count_const, (long) data_size));
13829
13830         /* Value stack is used to ensure reachability of constants and
13831          * inner functions being loaded.  Require enough space to handle
13832          * large functions correctly.
13833          */
13834         duk_require_stack(thr, (duk_idx_t) (2 + count_const + count_funcs));
13835         idx_base = duk_get_top(thr);
13836
13837         /* Push function object, init flags etc.  This must match
13838          * duk_js_push_closure() quite carefully.
13839          */
13840         h_fun = duk_push_hcompfunc(thr);
13841         DUK_ASSERT(h_fun != NULL);
13842         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun));
13843         DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL);
13844         DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL);
13845         DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL);
13846         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
13847
13848         h_fun->nregs = DUK_RAW_READ_U16_BE(p);
13849         h_fun->nargs = DUK_RAW_READ_U16_BE(p);
13850 #if defined(DUK_USE_DEBUGGER_SUPPORT)
13851         h_fun->start_line = DUK_RAW_READ_U32_BE(p);
13852         h_fun->end_line = DUK_RAW_READ_U32_BE(p);
13853 #else
13854         p += 8;  /* skip line info */
13855 #endif
13856
13857         /* duk_hcompfunc flags; quite version specific */
13858         tmp32 = DUK_RAW_READ_U32_BE(p);
13859         DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32);  /* masks flags to only change duk_hobject flags */
13860
13861         /* standard prototype (no need to set here, already set) */
13862         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
13863 #if 0
13864         DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
13865 #endif
13866
13867         /* assert just a few critical flags */
13868         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
13869         DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj));
13870         DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj));
13871         DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj));
13872         DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&h_fun->obj));
13873         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
13874         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
13875         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
13876
13877         /* Create function 'data' buffer but don't attach it yet. */
13878         fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, data_size);
13879         DUK_ASSERT(fun_data != NULL);
13880
13881         /* Load bytecode instructions. */
13882         DUK_ASSERT(sizeof(duk_instr_t) == 4);
13883         DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t));
13884 #if defined(DUK_USE_INTEGER_BE)
13885         q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
13886         duk_memcpy((void *) q,
13887                    (const void *) p,
13888                    sizeof(duk_instr_t) * count_instr);
13889         p += sizeof(duk_instr_t) * count_instr;
13890 #else
13891         q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
13892         for (n = count_instr; n > 0; n--) {
13893                 *((duk_instr_t *) (void *) q) = DUK_RAW_READ_U32_BE(p);
13894                 q += sizeof(duk_instr_t);
13895         }
13896 #endif
13897
13898         /* Load constants onto value stack but don't yet copy to buffer. */
13899         for (n = count_const; n > 0; n--) {
13900                 DUK__ASSERT_LEFT(1);
13901                 const_type = DUK_RAW_READ_U8(p);
13902                 switch (const_type) {
13903                 case DUK__SER_STRING: {
13904                         p = duk__load_string_raw(thr, p);
13905                         break;
13906                 }
13907                 case DUK__SER_NUMBER: {
13908                         /* Important to do a fastint check so that constants are
13909                          * properly read back as fastints.
13910                          */
13911                         duk_tval tv_tmp;
13912                         duk_double_t val;
13913                         DUK__ASSERT_LEFT(8);
13914                         val = DUK_RAW_READ_DOUBLE_BE(p);
13915                         DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val);
13916                         duk_push_tval(thr, &tv_tmp);
13917                         break;
13918                 }
13919                 default: {
13920                         goto format_error;
13921                 }
13922                 }
13923         }
13924
13925         /* Load inner functions to value stack, but don't yet copy to buffer. */
13926         for (n = count_funcs; n > 0; n--) {
13927                 p = duk__load_func(thr, p, p_end);
13928                 if (p == NULL) {
13929                         goto format_error;
13930                 }
13931         }
13932
13933         /* With constants and inner functions on value stack, we can now
13934          * atomically finish the function 'data' buffer, bump refcounts,
13935          * etc.
13936          *
13937          * Here we take advantage of the value stack being just a duk_tval
13938          * array: we can just memcpy() the constants as long as we incref
13939          * them afterwards.
13940          */
13941
13942         h_data = (duk_hbuffer *) duk_known_hbuffer(thr, idx_base + 1);
13943         DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
13944         DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data);
13945         DUK_HBUFFER_INCREF(thr, h_data);
13946
13947         tv1 = duk_get_tval(thr, idx_base + 2);  /* may be NULL if no constants or inner funcs */
13948         DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
13949
13950         q = fun_data;
13951         duk_memcpy_unsafe((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
13952         for (n = count_const; n > 0; n--) {
13953                 DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q);  /* no side effects */
13954                 q += sizeof(duk_tval);
13955         }
13956         tv1 += count_const;
13957
13958         DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
13959         for (n = count_funcs; n > 0; n--) {
13960                 duk_hobject *h_obj;
13961
13962                 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
13963                 h_obj = DUK_TVAL_GET_OBJECT(tv1);
13964                 DUK_ASSERT(h_obj != NULL);
13965                 tv1++;
13966                 DUK_HOBJECT_INCREF(thr, h_obj);
13967
13968                 *((duk_hobject **) (void *) q) = h_obj;
13969                 q += sizeof(duk_hobject *);
13970         }
13971
13972         DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
13973
13974         /* The function object is now reachable and refcounts are fine,
13975          * so we can pop off all the temporaries.
13976          */
13977         DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(thr, idx_base)));
13978         duk_set_top(thr, idx_base + 1);
13979
13980         /* Setup function properties. */
13981         tmp32 = DUK_RAW_READ_U32_BE(p);
13982         duk_push_u32(thr, tmp32);
13983         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
13984
13985 #if defined(DUK_USE_FUNC_NAME_PROPERTY)
13986         p = duk__load_string_raw(thr, p);  /* -> [ func funcname ] */
13987         func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
13988         DUK_ASSERT(func_env != NULL);
13989         need_pop = 0;
13990         if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
13991                 /* Original function instance/template had NAMEBINDING.
13992                  * Must create a lexical environment on loading to allow
13993                  * recursive functions like 'function foo() { foo(); }'.
13994                  */
13995                 duk_hdecenv *new_env;
13996
13997                 new_env = duk_hdecenv_alloc(thr,
13998                                             DUK_HOBJECT_FLAG_EXTENSIBLE |
13999                                             DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
14000                 DUK_ASSERT(new_env != NULL);
14001                 DUK_ASSERT(new_env->thread == NULL);  /* Closed. */
14002                 DUK_ASSERT(new_env->varmap == NULL);
14003                 DUK_ASSERT(new_env->regbase_byteoff == 0);
14004                 DUK_ASSERT_HDECENV_VALID(new_env);
14005                 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
14006                 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, func_env);
14007                 DUK_HOBJECT_INCREF(thr, func_env);
14008
14009                 func_env = (duk_hobject *) new_env;
14010
14011                 duk_push_hobject(thr, (duk_hobject *) new_env);
14012
14013                 duk_dup_m2(thr);                                  /* -> [ func funcname env funcname ] */
14014                 duk_dup(thr, idx_base);                           /* -> [ func funcname env funcname func ] */
14015                 duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE);  /* -> [ func funcname env ] */
14016
14017                 need_pop = 1;  /* Need to pop env, but -after- updating h_fun and increfs. */
14018         }
14019         DUK_ASSERT(func_env != NULL);
14020         DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env);
14021         DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env);
14022         DUK_HOBJECT_INCREF(thr, func_env);
14023         DUK_HOBJECT_INCREF(thr, func_env);
14024         if (need_pop) {
14025                 duk_pop(thr);
14026         }
14027         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
14028 #endif  /* DUK_USE_FUNC_NAME_PROPERTY */
14029
14030 #if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
14031         p = duk__load_string_raw(thr, p);
14032         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
14033 #endif  /* DUK_USE_FUNC_FILENAME_PROPERTY */
14034
14035         if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) {
14036                 /* Restore empty external .prototype only for constructable
14037                  * functions.
14038                  */
14039                 duk_push_object(thr);
14040                 duk_dup_m2(thr);
14041                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC);  /* func.prototype.constructor = func */
14042                 duk_compact_m1(thr);
14043                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
14044         }
14045
14046 #if defined(DUK_USE_PC2LINE)
14047         p = duk__load_buffer_raw(thr, p);
14048         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
14049 #endif  /* DUK_USE_PC2LINE */
14050
14051         duk_push_object(thr);  /* _Varmap */
14052         for (;;) {
14053                 /* XXX: awkward */
14054                 p = duk__load_string_raw(thr, p);
14055                 if (duk_get_length(thr, -1) == 0) {
14056                         duk_pop(thr);
14057                         break;
14058                 }
14059                 tmp32 = DUK_RAW_READ_U32_BE(p);
14060                 duk_push_u32(thr, tmp32);
14061                 duk_put_prop(thr, -3);
14062         }
14063         duk_compact_m1(thr);
14064         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
14065
14066         /* _Formals may have been missing in the original function, which is
14067          * handled using a marker length.
14068          */
14069         arr_limit = DUK_RAW_READ_U32_BE(p);
14070         if (arr_limit != DUK__NO_FORMALS) {
14071                 duk_push_array(thr);  /* _Formals */
14072                 for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) {
14073                         p = duk__load_string_raw(thr, p);
14074                         duk_put_prop_index(thr, -2, arr_idx);
14075                 }
14076                 duk_compact_m1(thr);
14077                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
14078         } else {
14079                 DUK_DD(DUK_DDPRINT("no _Formals in dumped function"));
14080         }
14081
14082         /* Return with final function pushed on stack top. */
14083         DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(thr, -1)));
14084         DUK_ASSERT_TOP(thr, idx_base + 1);
14085         return p;
14086
14087  format_error:
14088         return NULL;
14089 }
14090
14091 DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
14092         duk_hcompfunc *func;
14093         duk_bufwriter_ctx bw_ctx_alloc;
14094         duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
14095         duk_uint8_t *p;
14096
14097         DUK_ASSERT_API_ENTRY(thr);
14098
14099         /* Bound functions don't have all properties so we'd either need to
14100          * lookup the non-bound target function or reject bound functions.
14101          * For now, bound functions are rejected with TypeError.
14102          */
14103         func = duk_require_hcompfunc(thr, -1);
14104         DUK_ASSERT(func != NULL);
14105         DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj));
14106
14107         /* Estimating the result size beforehand would be costly, so
14108          * start with a reasonable size and extend as needed.
14109          */
14110         DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
14111         p = DUK_BW_GET_PTR(thr, bw_ctx);
14112         *p++ = DUK__SER_MARKER;
14113         p = duk__dump_func(thr, func, bw_ctx, p);
14114         DUK_BW_SET_PTR(thr, bw_ctx, p);
14115         DUK_BW_COMPACT(thr, bw_ctx);
14116
14117         DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(thr, -1)));
14118
14119         duk_remove_m2(thr);  /* [ ... func buf ] -> [ ... buf ] */
14120 }
14121
14122 DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
14123         duk_uint8_t *p_buf, *p, *p_end;
14124         duk_size_t sz;
14125
14126         DUK_ASSERT_API_ENTRY(thr);
14127
14128         p_buf = (duk_uint8_t *) duk_require_buffer(thr, -1, &sz);
14129         DUK_ASSERT(p_buf != NULL);
14130
14131         /* The caller is responsible for being sure that bytecode being loaded
14132          * is valid and trusted.  Invalid bytecode can cause memory unsafe
14133          * behavior directly during loading or later during bytecode execution
14134          * (instruction validation would be quite complex to implement).
14135          *
14136          * This signature check is the only sanity check for detecting
14137          * accidental invalid inputs.  The initial byte ensures no ordinary
14138          * string or Symbol will be accepted by accident.
14139          */
14140         p = p_buf;
14141         p_end = p_buf + sz;
14142         if (sz < 1 || p[0] != DUK__SER_MARKER) {
14143                 goto format_error;
14144         }
14145         p++;
14146
14147         p = duk__load_func(thr, p, p_end);
14148         if (p == NULL) {
14149                 goto format_error;
14150         }
14151
14152         duk_remove_m2(thr);  /* [ ... buf func ] -> [ ... func ] */
14153         return;
14154
14155  format_error:
14156         DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BYTECODE);
14157         DUK_WO_NORETURN(return;);
14158 }
14159
14160 #else  /* DUK_USE_BYTECODE_DUMP_SUPPORT */
14161
14162 DUK_EXTERNAL void duk_dump_function(duk_hthread *thr) {
14163         DUK_ASSERT_API_ENTRY(thr);
14164         DUK_ERROR_UNSUPPORTED(thr);
14165         DUK_WO_NORETURN(return;);
14166 }
14167
14168 DUK_EXTERNAL void duk_load_function(duk_hthread *thr) {
14169         DUK_ASSERT_API_ENTRY(thr);
14170         DUK_ERROR_UNSUPPORTED(thr);
14171         DUK_WO_NORETURN(return;);
14172 }
14173
14174 #endif  /* DUK_USE_BYTECODE_DUMP_SUPPORT */
14175
14176 /* automatic undefs */
14177 #undef DUK__ASSERT_LEFT
14178 #undef DUK__BYTECODE_INITIAL_ALLOC
14179 #undef DUK__NO_FORMALS
14180 #undef DUK__SER_MARKER
14181 #undef DUK__SER_NUMBER
14182 #undef DUK__SER_STRING
14183 #line 1 "duk_api_call.c"
14184 /*
14185  *  Calls.
14186  *
14187  *  Protected variants should avoid ever throwing an error.  Must be careful
14188  *  to catch errors related to value stack manipulation and property lookup,
14189  *  not just the call itself.
14190  *
14191  *  The only exception is when arguments are insane, e.g. nargs/nrets are out
14192  *  of bounds; in such cases an error is thrown for two reasons.  First, we
14193  *  can't always respect the value stack input/output guarantees in such cases
14194  *  so the caller would end up with the value stack in an unexpected state.
14195  *  Second, an attempt to create an error might itself fail (although this
14196  *  could be avoided by pushing a preallocated object/string or a primitive
14197  *  value).
14198  */
14199
14200 /* #include duk_internal.h -> already included */
14201
14202 /*
14203  *  Helpers
14204  */
14205
14206 struct duk__pcall_prop_args {
14207         duk_idx_t obj_idx;
14208         duk_idx_t nargs;
14209         duk_small_uint_t call_flags;
14210 };
14211 typedef struct duk__pcall_prop_args duk__pcall_prop_args;
14212
14213 struct duk__pcall_method_args {
14214         duk_idx_t nargs;
14215         duk_small_uint_t call_flags;
14216 };
14217 typedef struct duk__pcall_method_args duk__pcall_method_args;
14218
14219 struct duk__pcall_args {
14220         duk_idx_t nargs;
14221         duk_small_uint_t call_flags;
14222 };
14223 typedef struct duk__pcall_args duk__pcall_args;
14224
14225 /* Compute and validate idx_func for a certain 'nargs' and 'other'
14226  * parameter count (1 or 2, depending on whether 'this' binding is
14227  * present).
14228  */
14229 DUK_LOCAL duk_idx_t duk__call_get_idx_func(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
14230         duk_idx_t idx_func;
14231
14232         /* XXX: byte arithmetic? */
14233
14234         DUK_ASSERT(other >= 0);
14235
14236         idx_func = duk_get_top(thr) - nargs - other;
14237         if (DUK_UNLIKELY((idx_func | nargs) < 0)) {  /* idx_func < 0 || nargs < 0; OR sign bits */
14238                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14239                 DUK_WO_NORETURN(return 0;);
14240         }
14241         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14242         return idx_func;
14243 }
14244
14245 /* Compute idx_func, assume index will be valid.  This is a valid assumption
14246  * for protected calls: nargs < 0 is checked explicitly and duk_safe_call()
14247  * validates the argument count.
14248  */
14249 DUK_LOCAL duk_idx_t duk__call_get_idx_func_unvalidated(duk_hthread *thr, duk_idx_t nargs, duk_idx_t other) {
14250         duk_idx_t idx_func;
14251
14252         /* XXX: byte arithmetic? */
14253
14254         DUK_ASSERT(nargs >= 0);
14255         DUK_ASSERT(other >= 0);
14256
14257         idx_func = duk_get_top(thr) - nargs - other;
14258         DUK_ASSERT(idx_func >= 0);
14259         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14260         return idx_func;
14261 }
14262
14263 /* Prepare value stack for a method call through an object property.
14264  * May currently throw an error e.g. when getting the property.
14265  */
14266 DUK_LOCAL void duk__call_prop_prep_stack(duk_hthread *thr, duk_idx_t normalized_obj_idx, duk_idx_t nargs) {
14267         DUK_ASSERT_CTX_VALID(thr);
14268         DUK_ASSERT(nargs >= 0);
14269
14270         DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld",
14271                              (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(thr)));
14272
14273         /* [... key arg1 ... argN] */
14274
14275         /* duplicate key */
14276         duk_dup(thr, -nargs - 1);  /* Note: -nargs alone would fail for nargs == 0, this is OK */
14277         (void) duk_get_prop(thr, normalized_obj_idx);
14278
14279         DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(thr, -1)));
14280
14281 #if defined(DUK_USE_VERBOSE_ERRORS)
14282         if (DUK_UNLIKELY(!duk_is_callable(thr, -1))) {
14283                 duk_tval *tv_targ;
14284                 duk_tval *tv_base;
14285                 duk_tval *tv_key;
14286
14287                 tv_targ = DUK_GET_TVAL_NEGIDX(thr, -1);
14288                 tv_base = DUK_GET_TVAL_POSIDX(thr, normalized_obj_idx);
14289                 tv_key = DUK_GET_TVAL_NEGIDX(thr, -nargs - 2);
14290                 DUK_ASSERT(tv_targ >= thr->valstack_bottom && tv_targ < thr->valstack_top);
14291                 DUK_ASSERT(tv_base >= thr->valstack_bottom && tv_base < thr->valstack_top);
14292                 DUK_ASSERT(tv_key >= thr->valstack_bottom && tv_key < thr->valstack_top);
14293
14294                 duk_call_setup_propcall_error(thr, tv_targ, tv_base, tv_key);
14295         }
14296 #endif
14297
14298         /* [... key arg1 ... argN func] */
14299
14300         duk_replace(thr, -nargs - 2);
14301
14302         /* [... func arg1 ... argN] */
14303
14304         duk_dup(thr, normalized_obj_idx);
14305         duk_insert(thr, -nargs - 1);
14306
14307         /* [... func this arg1 ... argN] */
14308 }
14309
14310 DUK_EXTERNAL void duk_call(duk_hthread *thr, duk_idx_t nargs) {
14311         duk_small_uint_t call_flags;
14312         duk_idx_t idx_func;
14313
14314         DUK_ASSERT_API_ENTRY(thr);
14315
14316         idx_func = duk__call_get_idx_func(thr, nargs, 1);
14317         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14318
14319         duk_insert_undefined(thr, idx_func + 1);
14320
14321         call_flags = 0;  /* not protected, respect reclimit, not constructor */
14322         duk_handle_call_unprotected(thr, idx_func, call_flags);
14323 }
14324
14325 DUK_EXTERNAL void duk_call_method(duk_hthread *thr, duk_idx_t nargs) {
14326         duk_small_uint_t call_flags;
14327         duk_idx_t idx_func;
14328
14329         DUK_ASSERT_API_ENTRY(thr);
14330
14331         idx_func = duk__call_get_idx_func(thr, nargs, 2);
14332         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14333
14334         call_flags = 0;  /* not protected, respect reclimit, not constructor */
14335         duk_handle_call_unprotected(thr, idx_func, call_flags);
14336 }
14337
14338 DUK_EXTERNAL void duk_call_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
14339         /*
14340          *  XXX: if duk_handle_call() took values through indices, this could be
14341          *  made much more sensible.  However, duk_handle_call() needs to fudge
14342          *  the 'this' and 'func' values to handle bound functions, which is now
14343          *  done "in-place", so this is not a trivial change.
14344          */
14345
14346         DUK_ASSERT_API_ENTRY(thr);
14347
14348         obj_idx = duk_require_normalize_index(thr, obj_idx);  /* make absolute */
14349         if (DUK_UNLIKELY(nargs < 0)) {
14350                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14351                 DUK_WO_NORETURN(return;);
14352         }
14353
14354         duk__call_prop_prep_stack(thr, obj_idx, nargs);
14355
14356         duk_call_method(thr, nargs);
14357 }
14358
14359 DUK_LOCAL duk_ret_t duk__pcall_raw(duk_hthread *thr, void *udata) {
14360         duk__pcall_args *args;
14361         duk_idx_t idx_func;
14362         duk_int_t ret;
14363
14364         DUK_ASSERT_CTX_VALID(thr);
14365         DUK_ASSERT(udata != NULL);
14366
14367         args = (duk__pcall_args *) udata;
14368         idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 1);
14369         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14370
14371         duk_insert_undefined(thr, idx_func + 1);
14372
14373         ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
14374         DUK_ASSERT(ret == 0);
14375         DUK_UNREF(ret);
14376
14377         return 1;
14378 }
14379
14380 DUK_EXTERNAL duk_int_t duk_pcall(duk_hthread *thr, duk_idx_t nargs) {
14381         duk__pcall_args args;
14382
14383         DUK_ASSERT_API_ENTRY(thr);
14384
14385         args.nargs = nargs;
14386         if (DUK_UNLIKELY(nargs < 0)) {
14387                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14388                 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14389         }
14390         args.call_flags = 0;
14391
14392         return duk_safe_call(thr, duk__pcall_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
14393 }
14394
14395 DUK_LOCAL duk_ret_t duk__pcall_method_raw(duk_hthread *thr, void *udata) {
14396         duk__pcall_method_args *args;
14397         duk_idx_t idx_func;
14398         duk_int_t ret;
14399
14400         DUK_ASSERT_CTX_VALID(thr);
14401         DUK_ASSERT(udata != NULL);
14402
14403         args = (duk__pcall_method_args *) udata;
14404
14405         idx_func = duk__call_get_idx_func_unvalidated(thr, args->nargs, 2);
14406         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14407
14408         ret = duk_handle_call_unprotected(thr, idx_func, args->call_flags);
14409         DUK_ASSERT(ret == 0);
14410         DUK_UNREF(ret);
14411
14412         return 1;
14413 }
14414
14415 DUK_INTERNAL duk_int_t duk_pcall_method_flags(duk_hthread *thr, duk_idx_t nargs, duk_small_uint_t call_flags) {
14416         duk__pcall_method_args args;
14417
14418         DUK_ASSERT_API_ENTRY(thr);
14419
14420         args.nargs = nargs;
14421         if (DUK_UNLIKELY(nargs < 0)) {
14422                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14423                 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14424         }
14425         args.call_flags = call_flags;
14426
14427         return duk_safe_call(thr, duk__pcall_method_raw, (void *) &args /*udata*/, nargs + 2 /*nargs*/, 1 /*nrets*/);
14428 }
14429
14430 DUK_EXTERNAL duk_int_t duk_pcall_method(duk_hthread *thr, duk_idx_t nargs) {
14431         DUK_ASSERT_API_ENTRY(thr);
14432
14433         return duk_pcall_method_flags(thr, nargs, 0);
14434 }
14435
14436 DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_hthread *thr, void *udata) {
14437         duk__pcall_prop_args *args;
14438         duk_idx_t obj_idx;
14439         duk_int_t ret;
14440
14441         DUK_ASSERT_CTX_VALID(thr);
14442         DUK_ASSERT(udata != NULL);
14443
14444         args = (duk__pcall_prop_args *) udata;
14445
14446         obj_idx = duk_require_normalize_index(thr, args->obj_idx);  /* make absolute */
14447         duk__call_prop_prep_stack(thr, obj_idx, args->nargs);
14448
14449         ret = duk_handle_call_unprotected_nargs(thr, args->nargs, args->call_flags);
14450         DUK_ASSERT(ret == 0);
14451         DUK_UNREF(ret);
14452         return 1;
14453 }
14454
14455 DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t nargs) {
14456         duk__pcall_prop_args args;
14457
14458         DUK_ASSERT_API_ENTRY(thr);
14459
14460         args.obj_idx = obj_idx;
14461         args.nargs = nargs;
14462         if (DUK_UNLIKELY(nargs < 0)) {
14463                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14464                 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14465         }
14466         args.call_flags = 0;
14467
14468         return duk_safe_call(thr, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
14469 }
14470
14471 DUK_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) {
14472         duk_int_t rc;
14473
14474         DUK_ASSERT_API_ENTRY(thr);
14475
14476         /* nargs condition; fail if: top - bottom < nargs
14477          *                      <=>  top < bottom + nargs
14478          * nrets condition; fail if: end - (top - nargs) < nrets
14479          *                      <=>  end - top + nargs < nrets
14480          *                      <=>  end + nargs < top + nrets
14481          */
14482         /* XXX: check for any reserve? */
14483
14484         if (DUK_UNLIKELY((nargs | nrets) < 0 ||  /* nargs < 0 || nrets < 0; OR sign bits */
14485                          thr->valstack_top < thr->valstack_bottom + nargs ||        /* nargs too large compared to top */
14486                          thr->valstack_end + nargs < thr->valstack_top + nrets)) {  /* nrets too large compared to reserve */
14487                 DUK_D(DUK_DPRINT("not enough stack reserve for safe call or invalid arguments: "
14488                                  "nargs=%ld < 0 (?), nrets=%ld < 0 (?), top=%ld < bottom=%ld + nargs=%ld (?), "
14489                                  "end=%ld + nargs=%ld < top=%ld + nrets=%ld (?)",
14490                                   (long) nargs,
14491                                   (long) nrets,
14492                                   (long) (thr->valstack_top - thr->valstack),
14493                                   (long) (thr->valstack_bottom - thr->valstack),
14494                                   (long) nargs,
14495                                   (long) (thr->valstack_end - thr->valstack),
14496                                   (long) nargs,
14497                                   (long) (thr->valstack_top - thr->valstack),
14498                                   (long) nrets));
14499                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14500                 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14501         }
14502
14503         rc = duk_handle_safe_call(thr,           /* thread */
14504                                   func,          /* func */
14505                                   udata,         /* udata */
14506                                   nargs,         /* num_stack_args */
14507                                   nrets);        /* num_stack_res */
14508
14509         return rc;
14510 }
14511
14512 DUK_EXTERNAL void duk_new(duk_hthread *thr, duk_idx_t nargs) {
14513         duk_idx_t idx_func;
14514
14515         DUK_ASSERT_API_ENTRY(thr);
14516
14517         idx_func = duk__call_get_idx_func(thr, nargs, 1);
14518         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
14519
14520         duk_push_object(thr);  /* default instance; internal proto updated by call handling */
14521         duk_insert(thr, idx_func + 1);
14522
14523         duk_handle_call_unprotected(thr, idx_func, DUK_CALL_FLAG_CONSTRUCT);
14524 }
14525
14526 DUK_LOCAL duk_ret_t duk__pnew_helper(duk_hthread *thr, void *udata) {
14527         duk_idx_t nargs;
14528
14529         DUK_ASSERT(udata != NULL);
14530         nargs = *((duk_idx_t *) udata);
14531
14532         duk_new(thr, nargs);
14533         return 1;
14534 }
14535
14536 DUK_EXTERNAL duk_int_t duk_pnew(duk_hthread *thr, duk_idx_t nargs) {
14537         duk_int_t rc;
14538
14539         DUK_ASSERT_API_ENTRY(thr);
14540
14541         /* For now, just use duk_safe_call() to wrap duk_new().  We can't
14542          * simply use a protected duk_handle_call() because pushing the
14543          * default instance might throw.
14544          */
14545
14546         if (DUK_UNLIKELY(nargs < 0)) {
14547                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
14548                 DUK_WO_NORETURN(return DUK_EXEC_ERROR;);
14549         }
14550
14551         rc = duk_safe_call(thr, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
14552         return rc;
14553 }
14554
14555 DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_hthread *thr) {
14556         duk_activation *act;
14557
14558         DUK_ASSERT_API_ENTRY(thr);
14559
14560         act = thr->callstack_curr;
14561         if (act != NULL) {
14562                 return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
14563         }
14564         return 0;
14565 }
14566
14567 /* XXX: Make this obsolete by adding a function flag for rejecting a
14568  * non-constructor call automatically?
14569  */
14570 DUK_INTERNAL void duk_require_constructor_call(duk_hthread *thr) {
14571         DUK_ASSERT_API_ENTRY(thr);
14572
14573         if (!duk_is_constructor_call(thr)) {
14574                 DUK_ERROR_TYPE(thr, DUK_STR_CONSTRUCT_ONLY);
14575                 DUK_WO_NORETURN(return;);
14576         }
14577 }
14578
14579 DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_hthread *thr) {
14580         duk_activation *act;
14581
14582         /* For user code this could just return 1 (strict) always
14583          * because all Duktape/C functions are considered strict,
14584          * and strict is also the default when nothing is running.
14585          * However, Duktape may call this function internally when
14586          * the current activation is an ECMAScript function, so
14587          * this cannot be replaced by a 'return 1' without fixing
14588          * the internal call sites.
14589          */
14590
14591         DUK_ASSERT_API_ENTRY(thr);
14592
14593         act = thr->callstack_curr;
14594         if (act != NULL) {
14595                 return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
14596         } else {
14597                 /* Strict by default. */
14598                 return 1;
14599         }
14600 }
14601
14602 /*
14603  *  Duktape/C function magic
14604  */
14605
14606 DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_hthread *thr) {
14607         duk_activation *act;
14608         duk_hobject *func;
14609
14610         DUK_ASSERT_API_ENTRY(thr);
14611
14612         act = thr->callstack_curr;
14613         if (act) {
14614                 func = DUK_ACT_GET_FUNC(act);
14615                 if (!func) {
14616                         duk_tval *tv = &act->tv_func;
14617                         duk_small_uint_t lf_flags;
14618                         lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
14619                         return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
14620                 }
14621                 DUK_ASSERT(func != NULL);
14622
14623                 if (DUK_HOBJECT_IS_NATFUNC(func)) {
14624                         duk_hnatfunc *nf = (duk_hnatfunc *) func;
14625                         return (duk_int_t) nf->magic;
14626                 }
14627         }
14628         return 0;
14629 }
14630
14631 DUK_EXTERNAL duk_int_t duk_get_magic(duk_hthread *thr, duk_idx_t idx) {
14632         duk_tval *tv;
14633         duk_hobject *h;
14634
14635         DUK_ASSERT_API_ENTRY(thr);
14636
14637         tv = duk_require_tval(thr, idx);
14638         if (DUK_TVAL_IS_OBJECT(tv)) {
14639                 h = DUK_TVAL_GET_OBJECT(tv);
14640                 DUK_ASSERT(h != NULL);
14641                 if (!DUK_HOBJECT_HAS_NATFUNC(h)) {
14642                         goto type_error;
14643                 }
14644                 return (duk_int_t) ((duk_hnatfunc *) h)->magic;
14645         } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
14646                 duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
14647                 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
14648         }
14649
14650         /* fall through */
14651  type_error:
14652         DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
14653         DUK_WO_NORETURN(return 0;);
14654 }
14655
14656 DUK_EXTERNAL void duk_set_magic(duk_hthread *thr, duk_idx_t idx, duk_int_t magic) {
14657         duk_hnatfunc *nf;
14658
14659         DUK_ASSERT_API_ENTRY(thr);
14660
14661         nf = duk_require_hnatfunc(thr, idx);
14662         DUK_ASSERT(nf != NULL);
14663         nf->magic = (duk_int16_t) magic;
14664 }
14665
14666 /*
14667  *  Misc helpers
14668  */
14669
14670 /* Resolve a bound function on value stack top to a non-bound target
14671  * (leave other values as is).
14672  */
14673 DUK_INTERNAL void duk_resolve_nonbound_function(duk_hthread *thr) {
14674         duk_tval *tv;
14675
14676         DUK_ASSERT_HTHREAD_VALID(thr);
14677
14678         tv = DUK_GET_TVAL_NEGIDX(thr, -1);
14679         if (DUK_TVAL_IS_OBJECT(tv)) {
14680                 duk_hobject *h;
14681
14682                 h = DUK_TVAL_GET_OBJECT(tv);
14683                 DUK_ASSERT(h != NULL);
14684                 if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
14685                         duk_push_tval(thr, &((duk_hboundfunc *) (void *) h)->target);
14686                         duk_replace(thr, -2);
14687 #if 0
14688                         DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target);
14689                         DUK_TVAL_INCREF(thr, tv);
14690                         DUK_HOBJECT_DECREF_NORZ(thr, h);
14691 #endif
14692                         /* Rely on Function.prototype.bind() on never creating a bound
14693                          * function whose target is not proper.  This is now safe
14694                          * because the target is not even an internal property but a
14695                          * struct member.
14696                          */
14697                         DUK_ASSERT(duk_is_lightfunc(thr, -1) || duk_is_callable(thr, -1));
14698                 }
14699         }
14700
14701         /* Lightfuncs cannot be bound but are always callable and
14702          * constructable.
14703          */
14704 }
14705 #line 1 "duk_api_codec.c"
14706 /*
14707  *  Encoding and decoding basic formats: hex, base64.
14708  *
14709  *  These are in-place operations which may allow an optimized implementation.
14710  *
14711  *  Base-64: https://tools.ietf.org/html/rfc4648#section-4
14712  */
14713
14714 /* #include duk_internal.h -> already included */
14715
14716 /*
14717  *  Misc helpers
14718  */
14719
14720 /* Shared handling for encode/decode argument.  Fast path handling for
14721  * buffer and string values because they're the most common.  In particular,
14722  * avoid creating a temporary string or buffer when possible.
14723  */
14724 DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
14725         void *ptr;
14726         duk_bool_t isbuffer;
14727
14728         DUK_ASSERT(duk_is_valid_index(thr, idx));  /* checked by caller */
14729
14730         /* XXX: with def_ptr set to a stack related pointer, isbuffer could
14731          * be removed from the helper?
14732          */
14733         ptr = duk_get_buffer_data_raw(thr, idx, out_len, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, &isbuffer);
14734         if (isbuffer) {
14735                 DUK_ASSERT(*out_len == 0 || ptr != NULL);
14736                 return (const duk_uint8_t *) ptr;
14737         }
14738         return (const duk_uint8_t *) duk_to_lstring(thr, idx, out_len);
14739 }
14740
14741 /*
14742  *  Base64
14743  */
14744
14745 #if defined(DUK_USE_BASE64_SUPPORT)
14746 /* Bytes emitted for number of padding characters in range [0,4]. */
14747 DUK_LOCAL const duk_int8_t duk__base64_decode_nequal_step[5] = {
14748         3,   /* #### -> 24 bits, emit 3 bytes */
14749         2,   /* ###= -> 18 bits, emit 2 bytes */
14750         1,   /* ##== -> 12 bits, emit 1 byte */
14751         -1,  /* #=== -> 6 bits, error */
14752         0,   /* ==== -> 0 bits, emit 0 bytes */
14753 };
14754
14755 #if defined(DUK_USE_BASE64_FASTPATH)
14756 DUK_LOCAL const duk_uint8_t duk__base64_enctab_fast[64] = {
14757         0x41U, 0x42U, 0x43U, 0x44U, 0x45U, 0x46U, 0x47U, 0x48U, 0x49U, 0x4aU, 0x4bU, 0x4cU, 0x4dU, 0x4eU, 0x4fU, 0x50U,  /* A...P */
14758         0x51U, 0x52U, 0x53U, 0x54U, 0x55U, 0x56U, 0x57U, 0x58U, 0x59U, 0x5aU, 0x61U, 0x62U, 0x63U, 0x64U, 0x65U, 0x66U,  /* Q...f */
14759         0x67U, 0x68U, 0x69U, 0x6aU, 0x6bU, 0x6cU, 0x6dU, 0x6eU, 0x6fU, 0x70U, 0x71U, 0x72U, 0x73U, 0x74U, 0x75U, 0x76U,  /* g...v */
14760         0x77U, 0x78U, 0x79U, 0x7aU, 0x30U, 0x31U, 0x32U, 0x33U, 0x34U, 0x35U, 0x36U, 0x37U, 0x38U, 0x39U, 0x2bU, 0x2fU   /* w.../ */
14761 };
14762 #endif  /* DUK_USE_BASE64_FASTPATH */
14763
14764 #if defined(DUK_USE_BASE64_FASTPATH)
14765 /* Decode table for one byte of input:
14766  *   -1 = allowed whitespace
14767  *   -2 = padding
14768  *   -3 = error
14769  *    0...63 decoded bytes
14770  */
14771 DUK_LOCAL const duk_int8_t duk__base64_dectab_fast[256] = {
14772         -3, -3, -3, -3, -3, -3, -3, -3, -3, -1, -1, -3, -3, -1, -3, -3,  /* 0x00...0x0f */
14773         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,  /* 0x10...0x1f */
14774         -1, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 62, -3, -3, -3, 63,  /* 0x20...0x2f */
14775         52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -3, -3, -3, -2, -3, -3,  /* 0x30...0x3f */
14776         -3,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,  /* 0x40...0x4f */
14777         15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -3, -3, -3, -3, -3,  /* 0x50...0x5f */
14778         -3, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,  /* 0x60...0x6f */
14779         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -3, -3, -3, -3, -3,  /* 0x70...0x7f */
14780         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,  /* 0x80...0x8f */
14781         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,  /* 0x90...0x9f */
14782         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,  /* 0xa0...0xaf */
14783         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,  /* 0xb0...0xbf */
14784         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,  /* 0xc0...0xcf */
14785         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,  /* 0xd0...0xdf */
14786         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,  /* 0xe0...0xef */
14787         -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3   /* 0xf0...0xff */
14788 };
14789 #endif  /* DUK_USE_BASE64_FASTPATH */
14790
14791 #if defined(DUK_USE_BASE64_FASTPATH)
14792 DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_3(const duk_uint8_t *src, duk_uint8_t *dst) {
14793         duk_uint_t t;
14794
14795         t = (duk_uint_t) src[0];
14796         t = (t << 8) + (duk_uint_t) src[1];
14797         t = (t << 8) + (duk_uint_t) src[2];
14798
14799         dst[0] = duk__base64_enctab_fast[t >> 18];
14800         dst[1] = duk__base64_enctab_fast[(t >> 12) & 0x3fU];
14801         dst[2] = duk__base64_enctab_fast[(t >> 6) & 0x3fU];
14802         dst[3] = duk__base64_enctab_fast[t & 0x3fU];
14803
14804 #if 0
14805         /* Tested: not faster on x64, most likely due to aliasing between
14806          * output and input index computation.
14807          */
14808         /* aaaaaabb bbbbcccc ccdddddd */
14809         dst[0] = duk__base64_enctab_fast[(src[0] >> 2) & 0x3fU];
14810         dst[1] = duk__base64_enctab_fast[((src[0] << 4) & 0x30U) | ((src[1] >> 4) & 0x0fU)];
14811         dst[2] = duk__base64_enctab_fast[((src[1] << 2) & 0x3fU) | ((src[2] >> 6) & 0x03U)];
14812         dst[3] = duk__base64_enctab_fast[src[2] & 0x3fU];
14813 #endif
14814 }
14815
14816 DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_2(const duk_uint8_t *src, duk_uint8_t *dst) {
14817         duk_uint_t t;
14818
14819         t = (duk_uint_t) src[0];
14820         t = (t << 8) + (duk_uint_t) src[1];
14821         dst[0] = duk__base64_enctab_fast[t >> 10];           /* XXXXXX-- -------- */
14822         dst[1] = duk__base64_enctab_fast[(t >> 4) & 0x3fU];  /* ------XX XXXX---- */
14823         dst[2] = duk__base64_enctab_fast[(t << 2) & 0x3fU];  /* -------- ----XXXX */
14824         dst[3] = DUK_ASC_EQUALS;
14825 }
14826
14827 DUK_LOCAL DUK_ALWAYS_INLINE void duk__base64_encode_fast_1(const duk_uint8_t *src, duk_uint8_t *dst) {
14828         duk_uint_t t;
14829
14830         t = (duk_uint_t) src[0];
14831         dst[0] = duk__base64_enctab_fast[t >> 2];            /* XXXXXX-- */
14832         dst[1] = duk__base64_enctab_fast[(t << 4) & 0x3fU];  /* ------XX */
14833         dst[2] = DUK_ASC_EQUALS;
14834         dst[3] = DUK_ASC_EQUALS;
14835 }
14836
14837 DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
14838         duk_size_t n;
14839         const duk_uint8_t *p;
14840         duk_uint8_t *q;
14841
14842         n = srclen;
14843         p = src;
14844         q = dst;
14845
14846         if (n >= 16U) {
14847                 /* Fast path, unrolled by 4, allows interleaving.  Process
14848                  * 12-byte input chunks which encode to 16-char output chunks.
14849                  * Only enter when at least one block is emitted (avoids div+mul
14850                  * for short inputs too).
14851                  */
14852                 const duk_uint8_t *p_end_fast;
14853
14854                 p_end_fast = p + ((n / 12U) * 12U);
14855                 DUK_ASSERT(p_end_fast >= p + 12);
14856                 do {
14857                         duk__base64_encode_fast_3(p, q);
14858                         duk__base64_encode_fast_3(p + 3, q + 4);
14859                         duk__base64_encode_fast_3(p + 6, q + 8);
14860                         duk__base64_encode_fast_3(p + 9, q + 12);
14861                         p += 12;
14862                         q += 16;
14863                 } while (DUK_LIKELY(p != p_end_fast));
14864
14865                 DUK_ASSERT(src + srclen >= p);
14866                 n = (duk_size_t) (src + srclen - p);
14867                 DUK_ASSERT(n < 12U);
14868         }
14869
14870         /* Remainder. */
14871         while (n >= 3U) {
14872                 duk__base64_encode_fast_3(p, q);
14873                 p += 3;
14874                 q += 4;
14875                 n -= 3U;
14876         }
14877         DUK_ASSERT(n == 0U || n == 1U || n == 2U);
14878         if (n == 1U) {
14879                 duk__base64_encode_fast_1(p, q);
14880 #if 0  /* Unnecessary. */
14881                 p += 1;
14882                 q += 4;
14883                 n -= 1U;
14884 #endif
14885         } else if (n == 2U) {
14886                 duk__base64_encode_fast_2(p, q);
14887 #if 0  /* Unnecessary. */
14888                 p += 2;
14889                 q += 4;
14890                 n -= 2U;
14891 #endif
14892         } else {
14893                 DUK_ASSERT(n == 0U);  /* nothing to do */
14894                 ;
14895         }
14896 }
14897 #else  /* DUK_USE_BASE64_FASTPATH */
14898 DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
14899         duk_small_uint_t i, npad;
14900         duk_uint_t t, x, y;
14901         const duk_uint8_t *p;
14902         const duk_uint8_t *p_end;
14903         duk_uint8_t *q;
14904
14905         p = src;
14906         p_end = src + srclen;
14907         q = dst;
14908         npad = 0U;
14909
14910         while (p < p_end) {
14911                 /* Read 3 bytes into 't', padded by zero. */
14912                 t = 0;
14913                 for (i = 0; i < 3; i++) {
14914                         t = t << 8;
14915                         if (p < p_end) {
14916                                 t += (duk_uint_t) (*p++);
14917                         } else {
14918                                 /* This only happens on the last loop and we're
14919                                  * guaranteed to exit on the next loop.
14920                                  */
14921                                 npad++;
14922                         }
14923                 }
14924                 DUK_ASSERT(npad <= 2U);
14925
14926                 /* Emit 4 encoded characters.  If npad > 0, some of the
14927                  * chars will be incorrect (zero bits) but we fix up the
14928                  * padding after the loop.  A straightforward 64-byte
14929                  * lookup would be faster and cleaner, but this is shorter.
14930                  */
14931                 for (i = 0; i < 4; i++) {
14932                         x = ((t >> 18) & 0x3fU);
14933                         t = t << 6;
14934
14935                         if (x <= 51U) {
14936                                 if (x <= 25) {
14937                                         y = x + DUK_ASC_UC_A;
14938                                 } else {
14939                                         y = x - 26 + DUK_ASC_LC_A;
14940                                 }
14941                         } else {
14942                                 if (x <= 61U) {
14943                                         y = x - 52 + DUK_ASC_0;
14944                                 } else if (x == 62) {
14945                                         y = DUK_ASC_PLUS;
14946                                 } else {
14947                                         DUK_ASSERT(x == 63);
14948                                         y = DUK_ASC_SLASH;
14949                                 }
14950                         }
14951
14952                         *q++ = (duk_uint8_t) y;
14953                 }
14954         }
14955
14956         /* Handle padding by rewriting 0-2 bogus characters at the end.
14957          *
14958          *  Missing bytes    npad     base64 example
14959          *    0               0         ####
14960          *    1               1         ###=
14961          *    2               2         ##==
14962          */
14963         DUK_ASSERT(npad <= 2U);
14964         while (npad > 0U) {
14965                 *(q - npad) = DUK_ASC_EQUALS;
14966                 npad--;
14967         }
14968 }
14969 #endif  /* DUK_USE_BASE64_FASTPATH */
14970
14971 #if defined(DUK_USE_BASE64_FASTPATH)
14972 DUK_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) {
14973         duk_int_t x;
14974         duk_uint_t t;
14975         duk_small_uint_t n_equal;
14976         duk_int8_t step;
14977         const duk_uint8_t *p;
14978         const duk_uint8_t *p_end;
14979         const duk_uint8_t *p_end_safe;
14980         duk_uint8_t *q;
14981
14982         p = src;
14983         p_end = src + srclen;
14984         p_end_safe = p_end - 8;  /* If 'src <= src_end_safe', safe to read 8 bytes. */
14985         q = dst;
14986
14987         /* Alternate between a fast path which processes clean groups with no
14988          * padding or whitespace, and a slow path which processes one arbitrary
14989          * group and then re-enters the fast path.  This handles e.g. base64
14990          * with newlines reasonably well because the majority of a line is in
14991          * the fast path.
14992          */
14993         for (;;) {
14994                 /* Fast path, on each loop handle two 4-char input groups.
14995                  * If both are clean, emit 6 bytes and continue.  If first
14996                  * is clean, emit 3 bytes and drop out; otherwise emit
14997                  * nothing and drop out.  This approach could be extended to
14998                  * more groups per loop, but for inputs with e.g. periodic
14999                  * newlines (which are common) it might not be an improvement.
15000                  */
15001                 while (DUK_LIKELY(p <= p_end_safe)) {
15002                         duk_int_t t1, t2;
15003
15004                         /* The lookup byte is intentionally sign extended to
15005                          * (at least) 32 bits and then ORed.  This ensures
15006                          * that is at least 1 byte is negative, the highest
15007                          * bit of the accumulator will be set at the end and
15008                          * we don't need to check every byte.
15009                          *
15010                          * Read all input bytes first before writing output
15011                          * bytes to minimize aliasing.
15012                          */
15013                         DUK_DDD(DUK_DDDPRINT("fast loop: p=%p, p_end_safe=%p, p_end=%p",
15014                                              (const void *) p, (const void *) p_end_safe, (const void *) p_end));
15015
15016                         t1 = (duk_int_t) duk__base64_dectab_fast[p[0]];
15017                         t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[1]];
15018                         t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[2]];
15019                         t1 = (duk_int_t) ((duk_uint_t) t1 << 6) | (duk_int_t) duk__base64_dectab_fast[p[3]];
15020
15021                         t2 = (duk_int_t) duk__base64_dectab_fast[p[4]];
15022                         t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[5]];
15023                         t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[6]];
15024                         t2 = (duk_int_t) ((duk_uint_t) t2 << 6) | (duk_int_t) duk__base64_dectab_fast[p[7]];
15025
15026                         q[0] = (duk_uint8_t) (((duk_uint_t) t1 >> 16) & 0xffU);
15027                         q[1] = (duk_uint8_t) (((duk_uint_t) t1 >> 8) & 0xffU);
15028                         q[2] = (duk_uint8_t) ((duk_uint_t) t1 & 0xffU);
15029
15030                         q[3] = (duk_uint8_t) (((duk_uint_t) t2 >> 16) & 0xffU);
15031                         q[4] = (duk_uint8_t) (((duk_uint_t) t2 >> 8) & 0xffU);
15032                         q[5] = (duk_uint8_t) ((duk_uint_t) t2 & 0xffU);
15033
15034                         /* Optimistic check using one branch. */
15035                         if (DUK_LIKELY((t1 | t2) >= 0)) {
15036                                 p += 8;
15037                                 q += 6;
15038                         } else if (t1 >= 0) {
15039                                 DUK_DDD(DUK_DDDPRINT("fast loop first group was clean, second was not, process one slow path group"));
15040                                 DUK_ASSERT(t2 < 0);
15041                                 p += 4;
15042                                 q += 3;
15043                                 break;
15044                         } else {
15045                                 DUK_DDD(DUK_DDDPRINT("fast loop first group was not clean, second does not matter, process one slow path group"));
15046                                 DUK_ASSERT(t1 < 0);
15047                                 break;
15048                         }
15049                 }  /* fast path */
15050
15051                 /* Slow path step 1: try to scan a 4-character encoded group,
15052                  * end-of-input, or start-of-padding.  We exit with:
15053                  *   1. n_chars == 4: full group, no padding, no end-of-input.
15054                  *   2. n_chars < 4: partial group (may also be 0), encountered
15055                  *      padding or end of input.
15056                  *
15057                  * The accumulator is initialized to 1; this allows us to detect
15058                  * a full group by comparing >= 0x1000000 without an extra
15059                  * counter variable.
15060                  */
15061                 t = 1UL;
15062                 for (;;) {
15063                         DUK_DDD(DUK_DDDPRINT("slow loop: p=%p, p_end=%p, t=%lu",
15064                                              (const void *) p, (const void *) p_end, (unsigned long) t));
15065
15066                         if (DUK_LIKELY(p < p_end)) {
15067                                 x = duk__base64_dectab_fast[*p++];
15068                                 if (DUK_LIKELY(x >= 0)) {
15069                                         DUK_ASSERT(x >= 0 && x <= 63);
15070                                         t = (t << 6) + (duk_uint_t) x;
15071                                         if (t >= 0x1000000UL) {
15072                                                 break;
15073                                         }
15074                                 } else if (x == -1) {
15075                                         continue;  /* allowed ascii whitespace */
15076                                 } else if (x == -2) {
15077                                         p--;
15078                                         break;  /* start of padding */
15079                                 } else {
15080                                         DUK_ASSERT(x == -3);
15081                                         goto decode_error;
15082                                 }
15083                         } else {
15084                                 break;  /* end of input */
15085                         }
15086                 }  /* slow path step 1 */
15087
15088                 /* Complete the padding by simulating pad characters,
15089                  * regardless of actual input padding chars.
15090                  */
15091                 n_equal = 0;
15092                 while (t < 0x1000000UL) {
15093                         t = (t << 6) + 0U;
15094                         n_equal++;
15095                 }
15096
15097                 /* Slow path step 2: deal with full/partial group, padding,
15098                  * etc.  Note that for num chars in [0,3] we intentionally emit
15099                  * 3 bytes but don't step forward that much, buffer space is
15100                  * guaranteed in setup.
15101                  *
15102                  *  num chars:
15103                  *   0      ####   no output (= step 0)
15104                  *   1      #===   reject, 6 bits of data
15105                  *   2      ##==   12 bits of data, output 1 byte (= step 1)
15106                  *   3      ###=   18 bits of data, output 2 bytes (= step 2)
15107                  *   4      ####   24 bits of data, output 3 bytes (= step 3)
15108                  */
15109                 q[0] = (duk_uint8_t) ((t >> 16) & 0xffU);
15110                 q[1] = (duk_uint8_t) ((t >> 8) & 0xffU);
15111                 q[2] = (duk_uint8_t) (t & 0xffU);
15112
15113                 DUK_ASSERT(n_equal <= 4);
15114                 step = duk__base64_decode_nequal_step[n_equal];
15115                 if (DUK_UNLIKELY(step < 0)) {
15116                         goto decode_error;
15117                 }
15118                 q += step;
15119
15120                 /* Slow path step 3: read and ignore padding and whitespace
15121                  * until (a) next non-padding and non-whitespace character
15122                  * after which we resume the fast path, or (b) end of input.
15123                  * This allows us to accept missing, partial, full, and extra
15124                  * padding cases uniformly.  We also support concatenated
15125                  * base-64 documents because we resume scanning afterwards.
15126                  *
15127                  * Note that to support concatenated documents well, the '='
15128                  * padding found inside the input must also allow for 'extra'
15129                  * padding.  For example, 'Zm===' decodes to 'f' and has one
15130                  * extra padding char.  So, 'Zm===Zm' should decode 'ff', even
15131                  * though the standard break-up would be 'Zm==' + '=Zm' which
15132                  * doesn't make sense.
15133                  *
15134                  * We also accept prepended padding like '==Zm9', because it
15135                  * is equivalent to an empty document with extra padding ('==')
15136                  * followed by a valid document.
15137                  */
15138
15139                 for (;;) {
15140                         if (DUK_UNLIKELY(p >= p_end)) {
15141                                 goto done;
15142                         }
15143                         x = duk__base64_dectab_fast[*p++];
15144                         if (x == -1 || x == -2) {
15145                                 ;  /* padding or whitespace, keep eating */
15146                         } else {
15147                                 p--;
15148                                 break;  /* backtrack and go back to fast path, even for -1 */
15149                         }
15150                 }  /* slow path step 3 */
15151         }  /* outer fast+slow path loop */
15152
15153  done:
15154         DUK_DDD(DUK_DDDPRINT("done; p=%p, p_end=%p",
15155                              (const void *) p, (const void *) p_end));
15156
15157         DUK_ASSERT(p == p_end);
15158
15159         *out_dst_final = q;
15160         return 1;
15161
15162  decode_error:
15163         return 0;
15164 }
15165 #else  /* DUK_USE_BASE64_FASTPATH */
15166 DUK_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) {
15167         duk_uint_t t, x;
15168         duk_int_t y;
15169         duk_int8_t step;
15170         const duk_uint8_t *p;
15171         const duk_uint8_t *p_end;
15172         duk_uint8_t *q;
15173         /* 0x09, 0x0a, or 0x0d */
15174         duk_uint32_t mask_white = (1U << 9) | (1U << 10) | (1U << 13);
15175
15176         /* 't' tracks progress of the decoded group:
15177          *
15178          *  t == 1             no valid chars yet
15179          *  t >= 0x40          1x6 = 6 bits shifted in
15180          *  t >= 0x1000        2x6 = 12 bits shifted in
15181          *  t >= 0x40000       3x6 = 18 bits shifted in
15182          *  t >= 0x1000000     4x6 = 24 bits shifted in
15183          *
15184          * By initializing t=1 there's no need for a separate counter for
15185          * the number of characters found so far.
15186          */
15187         p = src;
15188         p_end = src + srclen;
15189         q = dst;
15190         t = 1UL;
15191
15192         for (;;) {
15193                 duk_small_uint_t n_equal;
15194
15195                 DUK_ASSERT(t >= 1U);
15196                 if (p >= p_end) {
15197                         /* End of input: if input exists, treat like
15198                          * start of padding, finish the block, then
15199                          * re-enter here to see we're done.
15200                          */
15201                         if (t == 1U) {
15202                                 break;
15203                         } else {
15204                                 goto simulate_padding;
15205                         }
15206                 }
15207
15208                 x = *p++;
15209
15210                 if (x >= 0x41U) {
15211                         /* Valid: a-z and A-Z. */
15212                         DUK_ASSERT(x >= 0x41U && x <= 0xffU);
15213                         if (x >= 0x61U && x <= 0x7aU) {
15214                                 y = (duk_int_t) x - 0x61 + 26;
15215                         } else if (x <= 0x5aU) {
15216                                 y = (duk_int_t) x - 0x41;
15217                         } else {
15218                                 goto decode_error;
15219                         }
15220                 } else if (x >= 0x30U) {
15221                         /* Valid: 0-9 and =. */
15222                         DUK_ASSERT(x >= 0x30U && x <= 0x40U);
15223                         if (x <= 0x39U) {
15224                                 y = (duk_int_t) x - 0x30 + 52;
15225                         } else if (x == 0x3dU) {
15226                                 /* Skip padding and whitespace unless we're in the
15227                                  * middle of a block.  Otherwise complete group by
15228                                  * simulating shifting in the correct padding.
15229                                  */
15230                                 if (t == 1U) {
15231                                         continue;
15232                                 }
15233                                 goto simulate_padding;
15234                         } else {
15235                                 goto decode_error;
15236                         }
15237                 } else if (x >= 0x20U) {
15238                         /* Valid: +, /, and 0x20 whitespace. */
15239                         DUK_ASSERT(x >= 0x20U && x <= 0x2fU);
15240                         if (x == 0x2bU) {
15241                                 y = 62;
15242                         } else if (x == 0x2fU) {
15243                                 y = 63;
15244                         } else if (x == 0x20U) {
15245                                 continue;
15246                         } else {
15247                                 goto decode_error;
15248                         }
15249                 } else {
15250                         /* Valid: whitespace. */
15251                         duk_uint32_t m;
15252                         DUK_ASSERT(x < 0x20U);  /* 0x00 to 0x1f */
15253                         m = (1U << x);
15254                         if (mask_white & m) {
15255                                 /* Allow basic ASCII whitespace. */
15256                                 continue;
15257                         } else {
15258                                 goto decode_error;
15259                         }
15260                 }
15261
15262                 DUK_ASSERT(y >= 0 && y <= 63);
15263                 t = (t << 6) + (duk_uint_t) y;
15264                 if (t < 0x1000000UL) {
15265                         continue;
15266                 }
15267                 /* fall through; no padding will be added */
15268
15269          simulate_padding:
15270                 n_equal = 0;
15271                 while (t < 0x1000000UL) {
15272                         t = (t << 6) + 0U;
15273                         n_equal++;
15274                 }
15275
15276                 /* Output 3 bytes from 't' and advance as needed. */
15277                 q[0] = (duk_uint8_t) ((t >> 16) & 0xffU);
15278                 q[1] = (duk_uint8_t) ((t >> 8) & 0xffU);
15279                 q[2] = (duk_uint8_t) (t & 0xffU);
15280
15281                 DUK_ASSERT(n_equal <= 4U);
15282                 step = duk__base64_decode_nequal_step[n_equal];
15283                 if (step < 0) {
15284                         goto decode_error;
15285                 }
15286                 q += step;
15287
15288                 /* Re-enter loop.  The actual padding characters are skipped
15289                  * by the main loop.  This handles cases like missing, partial,
15290                  * full, and extra padding, and allows parsing of concatenated
15291                  * documents (with extra padding) like: Zm===Zm.  Also extra
15292                  * prepended padding is accepted: ===Zm9v.
15293                  */
15294                 t = 1U;
15295         }
15296         DUK_ASSERT(t == 1UL);
15297
15298         *out_dst_final = q;
15299         return 1;
15300
15301  decode_error:
15302         return 0;
15303 }
15304 #endif  /* DUK_USE_BASE64_FASTPATH */
15305
15306 DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
15307         const duk_uint8_t *src;
15308         duk_size_t srclen;
15309         duk_size_t dstlen;
15310         duk_uint8_t *dst;
15311         const char *ret;
15312
15313         DUK_ASSERT_API_ENTRY(thr);
15314
15315         idx = duk_require_normalize_index(thr, idx);
15316         src = duk__prep_codec_arg(thr, idx, &srclen);
15317         /* Note: for srclen=0, src may be NULL */
15318
15319         /* Compute exact output length.  Computation must not wrap; this
15320          * limit works for 32-bit size_t:
15321          * >>> srclen = 3221225469
15322          * >>> '%x' % ((srclen + 2) / 3 * 4)
15323          * 'fffffffc'
15324          */
15325         if (srclen > 3221225469UL) {
15326                 goto type_error;
15327         }
15328         dstlen = (srclen + 2U) / 3U * 4U;
15329         dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, dstlen);
15330
15331         duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
15332
15333         ret = duk_buffer_to_string(thr, -1);  /* Safe, result is ASCII. */
15334         duk_replace(thr, idx);
15335         return ret;
15336
15337  type_error:
15338         DUK_ERROR_TYPE(thr, DUK_STR_BASE64_ENCODE_FAILED);
15339         DUK_WO_NORETURN(return NULL;);
15340 }
15341
15342 DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
15343         const duk_uint8_t *src;
15344         duk_size_t srclen;
15345         duk_size_t dstlen;
15346         duk_uint8_t *dst;
15347         duk_uint8_t *dst_final;
15348
15349         DUK_ASSERT_API_ENTRY(thr);
15350
15351         idx = duk_require_normalize_index(thr, idx);
15352         src = duk__prep_codec_arg(thr, idx, &srclen);
15353
15354         /* Round up and add safety margin.  Avoid addition before division to
15355          * avoid possibility of wrapping.  Margin includes +3 for rounding up,
15356          * and +3 for one extra group: the decoder may emit and then backtrack
15357          * a full group (3 bytes) from zero-sized input for technical reasons.
15358          * Similarly, 'xx' may ecause 1+3 = bytes to be emitted and then
15359          * backtracked.
15360          */
15361         dstlen = (srclen / 4) * 3 + 6;  /* upper limit, assuming no whitespace etc */
15362         dst = (duk_uint8_t *) duk_push_dynamic_buffer(thr, dstlen);
15363         /* Note: for dstlen=0, dst may be NULL */
15364
15365         if (!duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final)) {
15366                 goto type_error;
15367         }
15368
15369         /* XXX: convert to fixed buffer? */
15370         (void) duk_resize_buffer(thr, -1, (duk_size_t) (dst_final - dst));
15371         duk_replace(thr, idx);
15372         return;
15373
15374  type_error:
15375         DUK_ERROR_TYPE(thr, DUK_STR_BASE64_DECODE_FAILED);
15376         DUK_WO_NORETURN(return;);
15377 }
15378 #else  /* DUK_USE_BASE64_SUPPORT */
15379 DUK_EXTERNAL const char *duk_base64_encode(duk_hthread *thr, duk_idx_t idx) {
15380         DUK_UNREF(idx);
15381         DUK_ERROR_UNSUPPORTED(thr);
15382         DUK_WO_NORETURN(return;);
15383 }
15384
15385 DUK_EXTERNAL void duk_base64_decode(duk_hthread *thr, duk_idx_t idx) {
15386         DUK_UNREF(idx);
15387         DUK_ERROR_UNSUPPORTED(thr);
15388         DUK_WO_NORETURN(return;);
15389 }
15390 #endif  /* DUK_USE_BASE64_SUPPORT */
15391
15392 /*
15393  *  Hex
15394  */
15395
15396 #if defined(DUK_USE_HEX_SUPPORT)
15397 DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
15398         const duk_uint8_t *inp;
15399         duk_size_t len;
15400         duk_size_t i;
15401         duk_uint8_t *buf;
15402         const char *ret;
15403 #if defined(DUK_USE_HEX_FASTPATH)
15404         duk_size_t len_safe;
15405         duk_uint16_t *p16;
15406 #endif
15407
15408         DUK_ASSERT_API_ENTRY(thr);
15409
15410         idx = duk_require_normalize_index(thr, idx);
15411         inp = duk__prep_codec_arg(thr, idx, &len);
15412         DUK_ASSERT(inp != NULL || len == 0);
15413
15414         /* Fixed buffer, no zeroing because we'll fill all the data. */
15415         buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len * 2);
15416         DUK_ASSERT(buf != NULL);
15417
15418 #if defined(DUK_USE_HEX_FASTPATH)
15419         DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0);   /* pointer is aligned, guaranteed for fixed buffer */
15420         p16 = (duk_uint16_t *) (void *) buf;
15421         len_safe = len & ~0x03U;
15422         for (i = 0; i < len_safe; i += 4) {
15423                 p16[0] = duk_hex_enctab[inp[i]];
15424                 p16[1] = duk_hex_enctab[inp[i + 1]];
15425                 p16[2] = duk_hex_enctab[inp[i + 2]];
15426                 p16[3] = duk_hex_enctab[inp[i + 3]];
15427                 p16 += 4;
15428         }
15429         for (; i < len; i++) {
15430                 *p16++ = duk_hex_enctab[inp[i]];
15431         }
15432 #else  /* DUK_USE_HEX_FASTPATH */
15433         for (i = 0; i < len; i++) {
15434                 duk_small_uint_t t;
15435                 t = (duk_small_uint_t) inp[i];
15436                 buf[i*2 + 0] = duk_lc_digits[t >> 4];
15437                 buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
15438         }
15439 #endif  /* DUK_USE_HEX_FASTPATH */
15440
15441         /* XXX: Using a string return value forces a string intern which is
15442          * not always necessary.  As a rough performance measure, hex encode
15443          * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s
15444          * without string coercion.  Change to returning a buffer and let the
15445          * caller coerce to string if necessary?
15446          */
15447
15448         ret = duk_buffer_to_string(thr, -1);  /* Safe, result is ASCII. */
15449         duk_replace(thr, idx);
15450         return ret;
15451 }
15452
15453 DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
15454         const duk_uint8_t *inp;
15455         duk_size_t len;
15456         duk_size_t i;
15457         duk_int_t t;
15458         duk_uint8_t *buf;
15459 #if defined(DUK_USE_HEX_FASTPATH)
15460         duk_int_t chk;
15461         duk_uint8_t *p;
15462         duk_size_t len_safe;
15463 #endif
15464
15465         DUK_ASSERT_API_ENTRY(thr);
15466
15467         idx = duk_require_normalize_index(thr, idx);
15468         inp = duk__prep_codec_arg(thr, idx, &len);
15469         DUK_ASSERT(inp != NULL || len == 0);
15470
15471         if (len & 0x01) {
15472                 goto type_error;
15473         }
15474
15475         /* Fixed buffer, no zeroing because we'll fill all the data. */
15476         buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len / 2);
15477         DUK_ASSERT(buf != NULL);
15478
15479 #if defined(DUK_USE_HEX_FASTPATH)
15480         p = buf;
15481         len_safe = len & ~0x07U;
15482         for (i = 0; i < len_safe; i += 8) {
15483                 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) |
15484                     ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
15485                 chk = t;
15486                 p[0] = (duk_uint8_t) t;
15487                 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) |
15488                     ((duk_int_t) duk_hex_dectab[inp[i + 3]]);
15489                 chk |= t;
15490                 p[1] = (duk_uint8_t) t;
15491                 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) |
15492                     ((duk_int_t) duk_hex_dectab[inp[i + 5]]);
15493                 chk |= t;
15494                 p[2] = (duk_uint8_t) t;
15495                 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) |
15496                     ((duk_int_t) duk_hex_dectab[inp[i + 7]]);
15497                 chk |= t;
15498                 p[3] = (duk_uint8_t) t;
15499                 p += 4;
15500
15501                 /* Check if any lookup above had a negative result. */
15502                 if (DUK_UNLIKELY(chk < 0)) {
15503                         goto type_error;
15504                 }
15505         }
15506         for (; i < len; i += 2) {
15507                 /* First cast to duk_int_t to sign extend, second cast to
15508                  * duk_uint_t to avoid signed left shift, and final cast to
15509                  * duk_int_t result type.
15510                  */
15511                 t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) |
15512                                  ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]]));
15513                 if (DUK_UNLIKELY(t < 0)) {
15514                         goto type_error;
15515                 }
15516                 *p++ = (duk_uint8_t) t;
15517         }
15518 #else  /* DUK_USE_HEX_FASTPATH */
15519         for (i = 0; i < len; i += 2) {
15520                 /* For invalid characters the value -1 gets extended to
15521                  * at least 16 bits.  If either nybble is invalid, the
15522                  * resulting 't' will be < 0.
15523                  */
15524                 t = (duk_int_t) ((((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i]]) << 4U) |
15525                                  ((duk_uint_t) (duk_int_t) duk_hex_dectab[inp[i + 1]]));
15526                 if (DUK_UNLIKELY(t < 0)) {
15527                         goto type_error;
15528                 }
15529                 buf[i >> 1] = (duk_uint8_t) t;
15530         }
15531 #endif  /* DUK_USE_HEX_FASTPATH */
15532
15533         duk_replace(thr, idx);
15534         return;
15535
15536  type_error:
15537         DUK_ERROR_TYPE(thr, DUK_STR_HEX_DECODE_FAILED);
15538         DUK_WO_NORETURN(return;);
15539 }
15540 #else  /* DUK_USE_HEX_SUPPORT */
15541 DUK_EXTERNAL const char *duk_hex_encode(duk_hthread *thr, duk_idx_t idx) {
15542         DUK_UNREF(idx);
15543         DUK_ERROR_UNSUPPORTED(thr);
15544         DUK_WO_NORETURN(return;);
15545 }
15546 DUK_EXTERNAL void duk_hex_decode(duk_hthread *thr, duk_idx_t idx) {
15547         DUK_UNREF(idx);
15548         DUK_ERROR_UNSUPPORTED(thr);
15549         DUK_WO_NORETURN(return;);
15550 }
15551 #endif  /* DUK_USE_HEX_SUPPORT */
15552
15553 /*
15554  *  JSON
15555  */
15556
15557 #if defined(DUK_USE_JSON_SUPPORT)
15558 DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
15559 #if defined(DUK_USE_ASSERTIONS)
15560         duk_idx_t top_at_entry;
15561 #endif
15562         const char *ret;
15563
15564         DUK_ASSERT_API_ENTRY(thr);
15565 #if defined(DUK_USE_ASSERTIONS)
15566         top_at_entry = duk_get_top(thr);
15567 #endif
15568
15569         idx = duk_require_normalize_index(thr, idx);
15570         duk_bi_json_stringify_helper(thr,
15571                                      idx /*idx_value*/,
15572                                      DUK_INVALID_INDEX /*idx_replacer*/,
15573                                      DUK_INVALID_INDEX /*idx_space*/,
15574                                      0 /*flags*/);
15575         DUK_ASSERT(duk_is_string(thr, -1));
15576         duk_replace(thr, idx);
15577         ret = duk_get_string(thr, idx);
15578
15579         DUK_ASSERT(duk_get_top(thr) == top_at_entry);
15580
15581         return ret;
15582 }
15583
15584 DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
15585 #if defined(DUK_USE_ASSERTIONS)
15586         duk_idx_t top_at_entry;
15587 #endif
15588
15589         DUK_ASSERT_API_ENTRY(thr);
15590 #if defined(DUK_USE_ASSERTIONS)
15591         top_at_entry = duk_get_top(thr);
15592 #endif
15593
15594         idx = duk_require_normalize_index(thr, idx);
15595         duk_bi_json_parse_helper(thr,
15596                                  idx /*idx_value*/,
15597                                  DUK_INVALID_INDEX /*idx_reviver*/,
15598                                  0 /*flags*/);
15599         duk_replace(thr, idx);
15600
15601         DUK_ASSERT(duk_get_top(thr) == top_at_entry);
15602 }
15603 #else  /* DUK_USE_JSON_SUPPORT */
15604 DUK_EXTERNAL const char *duk_json_encode(duk_hthread *thr, duk_idx_t idx) {
15605         DUK_ASSERT_API_ENTRY(thr);
15606         DUK_UNREF(idx);
15607         DUK_ERROR_UNSUPPORTED(thr);
15608         DUK_WO_NORETURN(return NULL;);
15609 }
15610
15611 DUK_EXTERNAL void duk_json_decode(duk_hthread *thr, duk_idx_t idx) {
15612         DUK_ASSERT_API_ENTRY(thr);
15613         DUK_UNREF(idx);
15614         DUK_ERROR_UNSUPPORTED(thr);
15615         DUK_WO_NORETURN(return;);
15616 }
15617 #endif  /* DUK_USE_JSON_SUPPORT */
15618 #line 1 "duk_api_compile.c"
15619 /*
15620  *  Compilation and evaluation
15621  */
15622
15623 /* #include duk_internal.h -> already included */
15624
15625 typedef struct duk__compile_raw_args duk__compile_raw_args;
15626 struct duk__compile_raw_args {
15627         duk_size_t src_length;  /* should be first on 64-bit platforms */
15628         const duk_uint8_t *src_buffer;
15629         duk_uint_t flags;
15630 };
15631
15632 /* Eval is just a wrapper now. */
15633 DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
15634         duk_int_t rc;
15635
15636         DUK_ASSERT_API_ENTRY(thr);
15637
15638         /* Note: strictness is *not* inherited from the current Duktape/C.
15639          * This would be confusing because the current strictness state
15640          * depends on whether we're running inside a Duktape/C activation
15641          * (= strict mode) or outside of any activation (= non-strict mode).
15642          * See tests/api/test-eval-strictness.c for more discussion.
15643          */
15644
15645         /* [ ... source? filename? ] (depends on flags) */
15646
15647         rc = duk_compile_raw(thr, src_buffer, src_length, flags | DUK_COMPILE_EVAL);  /* may be safe, or non-safe depending on flags */
15648
15649         /* [ ... closure/error ] */
15650
15651         if (rc != DUK_EXEC_SUCCESS) {
15652                 rc = DUK_EXEC_ERROR;
15653                 goto got_rc;
15654         }
15655
15656         duk_push_global_object(thr);  /* explicit 'this' binding, see GH-164 */
15657
15658         if (flags & DUK_COMPILE_SAFE) {
15659                 rc = duk_pcall_method(thr, 0);
15660         } else {
15661                 duk_call_method(thr, 0);
15662                 rc = DUK_EXEC_SUCCESS;
15663         }
15664
15665         /* [ ... result/error ] */
15666
15667  got_rc:
15668         if (flags & DUK_COMPILE_NORESULT) {
15669                 duk_pop(thr);
15670         }
15671
15672         return rc;
15673 }
15674
15675 /* Helper which can be called both directly and with duk_safe_call(). */
15676 DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) {
15677         duk__compile_raw_args *comp_args;
15678         duk_uint_t flags;
15679         duk_hcompfunc *h_templ;
15680
15681         DUK_ASSERT_CTX_VALID(thr);
15682         DUK_ASSERT(udata != NULL);
15683
15684         /* Note: strictness is not inherited from the current Duktape/C
15685          * context.  Otherwise it would not be possible to compile
15686          * non-strict code inside a Duktape/C activation (which is
15687          * always strict now).  See tests/api/test-eval-strictness.c
15688          * for discussion.
15689          */
15690
15691         /* [ ... source? filename? ] (depends on flags) */
15692
15693         comp_args = (duk__compile_raw_args *) udata;
15694         flags = comp_args->flags;
15695
15696         if (flags & DUK_COMPILE_NOFILENAME) {
15697                 /* Automatic filename: 'eval' or 'input'. */
15698                 duk_push_hstring_stridx(thr, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
15699         }
15700
15701         /* [ ... source? filename ] */
15702
15703         if (!comp_args->src_buffer) {
15704                 duk_hstring *h_sourcecode;
15705
15706                 h_sourcecode = duk_get_hstring(thr, -2);
15707                 if ((flags & DUK_COMPILE_NOSOURCE) ||  /* args incorrect */
15708                     (h_sourcecode == NULL)) {          /* e.g. duk_push_string_file_raw() pushed undefined */
15709                         DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
15710                         DUK_WO_NORETURN(return 0;);
15711                 }
15712                 DUK_ASSERT(h_sourcecode != NULL);
15713                 comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
15714                 comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
15715         }
15716         DUK_ASSERT(comp_args->src_buffer != NULL);
15717
15718         if (flags & DUK_COMPILE_FUNCTION) {
15719                 flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR;
15720         }
15721
15722         /* [ ... source? filename ] */
15723
15724         duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags);
15725
15726         /* [ ... source? func_template ] */
15727
15728         if (flags & DUK_COMPILE_NOSOURCE) {
15729                 ;
15730         } else {
15731                 duk_remove_m2(thr);
15732         }
15733
15734         /* [ ... func_template ] */
15735
15736         h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -1);
15737         duk_js_push_closure(thr,
15738                            h_templ,
15739                            thr->builtins[DUK_BIDX_GLOBAL_ENV],
15740                            thr->builtins[DUK_BIDX_GLOBAL_ENV],
15741                            1 /*add_auto_proto*/);
15742         duk_remove_m2(thr);   /* -> [ ... closure ] */
15743
15744         /* [ ... closure ] */
15745
15746         return 1;
15747 }
15748
15749 DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
15750         duk__compile_raw_args comp_args_alloc;
15751         duk__compile_raw_args *comp_args = &comp_args_alloc;
15752
15753         DUK_ASSERT_API_ENTRY(thr);
15754
15755         if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
15756                 /* String length is computed here to avoid multiple evaluation
15757                  * of a macro argument in the calling side.
15758                  */
15759                 src_length = DUK_STRLEN(src_buffer);
15760         }
15761
15762         comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
15763         comp_args->src_length = src_length;
15764         comp_args->flags = flags;
15765
15766         /* [ ... source? filename? ] (depends on flags) */
15767
15768         if (flags & DUK_COMPILE_SAFE) {
15769                 duk_int_t rc;
15770                 duk_int_t nargs;
15771                 duk_int_t nrets = 1;
15772
15773                 /* Arguments can be: [ source? filename? &comp_args] so that
15774                  * nargs is 1 to 3.  Call site encodes the correct nargs count
15775                  * directly into flags.
15776                  */
15777                 nargs = flags & 0x07;
15778                 DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
15779                                     ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1));
15780                 rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets);
15781
15782                 /* [ ... closure ] */
15783                 return rc;
15784         }
15785
15786         (void) duk__do_compile(thr, (void *) comp_args);
15787
15788         /* [ ... closure ] */
15789         return DUK_EXEC_SUCCESS;
15790 }
15791 #line 1 "duk_api_debug.c"
15792 /*
15793  *  Debugging related API calls
15794  */
15795
15796 /* #include duk_internal.h -> already included */
15797
15798 #if defined(DUK_USE_JSON_SUPPORT)
15799 DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
15800         duk_idx_t idx;
15801         duk_idx_t top;
15802
15803         DUK_ASSERT_API_ENTRY(thr);
15804
15805         /* We don't duk_require_stack() here now, but rely on the caller having
15806          * enough space.
15807          */
15808
15809         top = duk_get_top(thr);
15810         duk_push_array(thr);
15811         for (idx = 0; idx < top; idx++) {
15812                 duk_dup(thr, idx);
15813                 duk_put_prop_index(thr, -2, (duk_uarridx_t) idx);
15814         }
15815
15816         /* XXX: conversion errors should not propagate outwards.
15817          * Perhaps values need to be coerced individually?
15818          */
15819         duk_bi_json_stringify_helper(thr,
15820                                      duk_get_top_index(thr),  /*idx_value*/
15821                                      DUK_INVALID_INDEX,  /*idx_replacer*/
15822                                      DUK_INVALID_INDEX,  /*idx_space*/
15823                                      DUK_JSON_FLAG_EXT_CUSTOM |
15824                                      DUK_JSON_FLAG_ASCII_ONLY |
15825                                      DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
15826
15827         duk_push_sprintf(thr, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(thr, -1));
15828         duk_replace(thr, -3);  /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
15829         duk_pop(thr);
15830         DUK_ASSERT(duk_is_string(thr, -1));
15831 }
15832 #else  /* DUK_USE_JSON_SUPPORT */
15833 DUK_EXTERNAL void duk_push_context_dump(duk_hthread *thr) {
15834         DUK_ASSERT_API_ENTRY(thr);
15835         DUK_ERROR_UNSUPPORTED(thr);
15836         DUK_WO_NORETURN(return;);
15837 }
15838 #endif  /* DUK_USE_JSON_SUPPORT */
15839
15840 #if defined(DUK_USE_DEBUGGER_SUPPORT)
15841
15842 DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
15843                                       duk_debug_read_function read_cb,
15844                                       duk_debug_write_function write_cb,
15845                                       duk_debug_peek_function peek_cb,
15846                                       duk_debug_read_flush_function read_flush_cb,
15847                                       duk_debug_write_flush_function write_flush_cb,
15848                                       duk_debug_request_function request_cb,
15849                                       duk_debug_detached_function detached_cb,
15850                                       void *udata) {
15851         duk_heap *heap;
15852         const char *str;
15853         duk_size_t len;
15854
15855         /* XXX: should there be an error or an automatic detach if
15856          * already attached?
15857          */
15858
15859         DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
15860
15861         DUK_ASSERT_API_ENTRY(thr);
15862         DUK_ASSERT(read_cb != NULL);
15863         DUK_ASSERT(write_cb != NULL);
15864         /* Other callbacks are optional. */
15865
15866         heap = thr->heap;
15867         heap->dbg_read_cb = read_cb;
15868         heap->dbg_write_cb = write_cb;
15869         heap->dbg_peek_cb = peek_cb;
15870         heap->dbg_read_flush_cb = read_flush_cb;
15871         heap->dbg_write_flush_cb = write_flush_cb;
15872         heap->dbg_request_cb = request_cb;
15873         heap->dbg_detached_cb = detached_cb;
15874         heap->dbg_udata = udata;
15875         heap->dbg_have_next_byte = 0;
15876
15877         /* Start in paused state. */
15878         heap->dbg_processing = 0;
15879         heap->dbg_state_dirty = 0;
15880         heap->dbg_force_restart = 0;
15881         heap->dbg_pause_flags = 0;
15882         heap->dbg_pause_act = NULL;
15883         heap->dbg_pause_startline = 0;
15884         heap->dbg_exec_counter = 0;
15885         heap->dbg_last_counter = 0;
15886         heap->dbg_last_time = 0.0;
15887         duk_debug_set_paused(heap);  /* XXX: overlap with fields above */
15888
15889         /* Send version identification and flush right afterwards.  Note that
15890          * we must write raw, unframed bytes here.
15891          */
15892         duk_push_sprintf(thr, "%ld %ld %s %s\n",
15893                          (long) DUK_DEBUG_PROTOCOL_VERSION,
15894                          (long) DUK_VERSION,
15895                          (const char *) DUK_GIT_DESCRIBE,
15896                          (const char *) DUK_USE_TARGET_INFO);
15897         str = duk_get_lstring(thr, -1, &len);
15898         DUK_ASSERT(str != NULL);
15899         duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
15900         duk_debug_write_flush(thr);
15901         duk_pop(thr);
15902 }
15903
15904 DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
15905         DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
15906
15907         DUK_ASSERT_API_ENTRY(thr);
15908         DUK_ASSERT(thr->heap != NULL);
15909
15910         /* Can be called multiple times with no harm. */
15911         duk_debug_do_detach(thr->heap);
15912 }
15913
15914 DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
15915         duk_bool_t processed_messages;
15916
15917         DUK_ASSERT_API_ENTRY(thr);
15918         DUK_ASSERT(thr->heap != NULL);
15919
15920         if (!duk_debug_is_attached(thr->heap)) {
15921                 return;
15922         }
15923         if (thr->callstack_curr != NULL || thr->heap->dbg_processing) {
15924                 /* Calling duk_debugger_cooperate() while Duktape is being
15925                  * called into is not supported.  This is not a 100% check
15926                  * but prevents any damage in most cases.
15927                  */
15928                 return;
15929         }
15930
15931         processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/);
15932         DUK_UNREF(processed_messages);
15933 }
15934
15935 DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
15936         duk_idx_t top;
15937         duk_idx_t idx;
15938         duk_bool_t ret = 0;
15939
15940         DUK_ASSERT_API_ENTRY(thr);
15941         DUK_ASSERT(thr->heap != NULL);
15942
15943         DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
15944
15945         top = duk_get_top(thr);
15946         if (top < nvalues) {
15947                 DUK_ERROR_RANGE(thr, "not enough stack values for notify");
15948                 DUK_WO_NORETURN(return 0;);
15949         }
15950         if (duk_debug_is_attached(thr->heap)) {
15951                 duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
15952                 for (idx = top - nvalues; idx < top; idx++) {
15953                         duk_tval *tv = DUK_GET_TVAL_POSIDX(thr, idx);
15954                         duk_debug_write_tval(thr, tv);
15955                 }
15956                 duk_debug_write_eom(thr);
15957
15958                 /* Return non-zero (true) if we have a good reason to believe
15959                  * the notify was delivered; if we're still attached at least
15960                  * a transport error was not indicated by the transport write
15961                  * callback.  This is not a 100% guarantee of course.
15962                  */
15963                 if (duk_debug_is_attached(thr->heap)) {
15964                         ret = 1;
15965                 }
15966         }
15967         duk_pop_n(thr, nvalues);
15968         return ret;
15969 }
15970
15971 DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
15972         DUK_ASSERT_API_ENTRY(thr);
15973         DUK_ASSERT(thr->heap != NULL);
15974
15975         DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
15976
15977         /* Treat like a debugger statement: ignore when not attached. */
15978         if (duk_debug_is_attached(thr->heap)) {
15979                 if (duk_debug_is_paused(thr->heap)) {
15980                         DUK_D(DUK_DPRINT("duk_debugger_pause() called when already paused; ignoring"));
15981                 } else {
15982                         duk_debug_set_paused(thr->heap);
15983
15984                         /* Pause on the next opcode executed.  This is always safe to do even
15985                          * inside the debugger message loop: the interrupt counter will be reset
15986                          * to its proper value when the message loop exits.
15987                          */
15988                         thr->interrupt_init = 1;
15989                         thr->interrupt_counter = 0;
15990                 }
15991         }
15992 }
15993
15994 #else  /* DUK_USE_DEBUGGER_SUPPORT */
15995
15996 DUK_EXTERNAL void duk_debugger_attach(duk_hthread *thr,
15997                                       duk_debug_read_function read_cb,
15998                                       duk_debug_write_function write_cb,
15999                                       duk_debug_peek_function peek_cb,
16000                                       duk_debug_read_flush_function read_flush_cb,
16001                                       duk_debug_write_flush_function write_flush_cb,
16002                                       duk_debug_request_function request_cb,
16003                                       duk_debug_detached_function detached_cb,
16004                                       void *udata) {
16005         DUK_ASSERT_API_ENTRY(thr);
16006         DUK_UNREF(read_cb);
16007         DUK_UNREF(write_cb);
16008         DUK_UNREF(peek_cb);
16009         DUK_UNREF(read_flush_cb);
16010         DUK_UNREF(write_flush_cb);
16011         DUK_UNREF(request_cb);
16012         DUK_UNREF(detached_cb);
16013         DUK_UNREF(udata);
16014         DUK_ERROR_TYPE(thr, "no debugger support");
16015         DUK_WO_NORETURN(return;);
16016 }
16017
16018 DUK_EXTERNAL void duk_debugger_detach(duk_hthread *thr) {
16019         DUK_ASSERT_API_ENTRY(thr);
16020         DUK_ERROR_TYPE(thr, "no debugger support");
16021         DUK_WO_NORETURN(return;);
16022 }
16023
16024 DUK_EXTERNAL void duk_debugger_cooperate(duk_hthread *thr) {
16025         /* nop */
16026         DUK_ASSERT_API_ENTRY(thr);
16027         DUK_UNREF(thr);
16028 }
16029
16030 DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_hthread *thr, duk_idx_t nvalues) {
16031         duk_idx_t top;
16032
16033         DUK_ASSERT_API_ENTRY(thr);
16034
16035         top = duk_get_top(thr);
16036         if (top < nvalues) {
16037                 DUK_ERROR_RANGE_INVALID_COUNT(thr);
16038                 DUK_WO_NORETURN(return 0;);
16039         }
16040
16041         /* No debugger support, just pop values. */
16042         duk_pop_n(thr, nvalues);
16043         return 0;
16044 }
16045
16046 DUK_EXTERNAL void duk_debugger_pause(duk_hthread *thr) {
16047         /* Treat like debugger statement: nop */
16048         DUK_ASSERT_API_ENTRY(thr);
16049         DUK_UNREF(thr);
16050 }
16051
16052 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
16053 #line 1 "duk_api_heap.c"
16054 /*
16055  *  Heap creation and destruction
16056  */
16057
16058 /* #include duk_internal.h -> already included */
16059
16060 typedef struct duk_internal_thread_state duk_internal_thread_state;
16061
16062 struct duk_internal_thread_state {
16063         duk_ljstate lj;
16064         duk_bool_t creating_error;
16065         duk_hthread *curr_thread;
16066         duk_int_t call_recursion_depth;
16067 };
16068
16069 DUK_EXTERNAL duk_hthread *duk_create_heap(duk_alloc_function alloc_func,
16070                                           duk_realloc_function realloc_func,
16071                                           duk_free_function free_func,
16072                                           void *heap_udata,
16073                                           duk_fatal_function fatal_handler) {
16074         duk_heap *heap = NULL;
16075         duk_hthread *thr;
16076
16077         /* Assume that either all memory funcs are NULL or non-NULL, mixed
16078          * cases will now be unsafe.
16079          */
16080
16081         /* XXX: just assert non-NULL values here and make caller arguments
16082          * do the defaulting to the default implementations (smaller code)?
16083          */
16084
16085         if (!alloc_func) {
16086                 DUK_ASSERT(realloc_func == NULL);
16087                 DUK_ASSERT(free_func == NULL);
16088 #if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
16089                 alloc_func = duk_default_alloc_function;
16090                 realloc_func = duk_default_realloc_function;
16091                 free_func = duk_default_free_function;
16092 #else
16093                 DUK_D(DUK_DPRINT("no allocation functions given and no default providers"));
16094                 return NULL;
16095 #endif
16096         } else {
16097                 DUK_ASSERT(realloc_func != NULL);
16098                 DUK_ASSERT(free_func != NULL);
16099         }
16100
16101         if (!fatal_handler) {
16102                 fatal_handler = duk_default_fatal_handler;
16103         }
16104
16105         DUK_ASSERT(alloc_func != NULL);
16106         DUK_ASSERT(realloc_func != NULL);
16107         DUK_ASSERT(free_func != NULL);
16108         DUK_ASSERT(fatal_handler != NULL);
16109
16110         heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler);
16111         if (!heap) {
16112                 return NULL;
16113         }
16114         thr = heap->heap_thread;
16115         DUK_ASSERT(thr != NULL);
16116         DUK_ASSERT(thr->heap != NULL);
16117         return thr;
16118 }
16119
16120 DUK_EXTERNAL void duk_destroy_heap(duk_hthread *thr) {
16121         duk_heap *heap;
16122
16123         if (!thr) {
16124                 return;
16125         }
16126         DUK_ASSERT_API_ENTRY(thr);
16127         heap = thr->heap;
16128         DUK_ASSERT(heap != NULL);
16129
16130         duk_heap_free(heap);
16131 }
16132
16133 DUK_EXTERNAL void duk_suspend(duk_hthread *thr, duk_thread_state *state) {
16134         duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
16135         duk_heap *heap;
16136         duk_ljstate *lj;
16137
16138         DUK_ASSERT_API_ENTRY(thr);
16139         DUK_ASSERT(thr->heap != NULL);
16140         DUK_ASSERT(state != NULL);  /* unvalidated */
16141
16142         /* Currently not supported when called from within a finalizer.
16143          * If that is done, the finalizer will remain running indefinitely,
16144          * preventing other finalizers from executing.  The assert is a bit
16145          * wider, checking that it would be OK to run pending finalizers.
16146          */
16147         DUK_ASSERT(thr->heap->pf_prevent_count == 0);
16148
16149         /* Currently not supported to duk_suspend() from an errCreate()
16150          * call.
16151          */
16152         DUK_ASSERT(thr->heap->creating_error == 0);
16153
16154         heap = thr->heap;
16155         lj = &heap->lj;
16156
16157         duk_push_tval(thr, &lj->value1);
16158         duk_push_tval(thr, &lj->value2);
16159
16160         /* XXX: creating_error == 0 is asserted above, so no need to store. */
16161         duk_memcpy((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
16162         snapshot->creating_error = heap->creating_error;
16163         snapshot->curr_thread = heap->curr_thread;
16164         snapshot->call_recursion_depth = heap->call_recursion_depth;
16165
16166         lj->jmpbuf_ptr = NULL;
16167         lj->type = DUK_LJ_TYPE_UNKNOWN;
16168         DUK_TVAL_SET_UNDEFINED(&lj->value1);
16169         DUK_TVAL_SET_UNDEFINED(&lj->value2);
16170         heap->creating_error = 0;
16171         heap->curr_thread = NULL;
16172         heap->call_recursion_depth = 0;
16173 }
16174
16175 DUK_EXTERNAL void duk_resume(duk_hthread *thr, const duk_thread_state *state) {
16176         const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
16177         duk_heap *heap;
16178
16179         DUK_ASSERT_API_ENTRY(thr);
16180         DUK_ASSERT(thr->heap != NULL);
16181         DUK_ASSERT(state != NULL);  /* unvalidated */
16182
16183         /* Shouldn't be necessary if duk_suspend() is called before
16184          * duk_resume(), but assert in case API sequence is incorrect.
16185          */
16186         DUK_ASSERT(thr->heap->pf_prevent_count == 0);
16187         DUK_ASSERT(thr->heap->creating_error == 0);
16188
16189         heap = thr->heap;
16190
16191         duk_memcpy((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
16192         heap->creating_error = snapshot->creating_error;
16193         heap->curr_thread = snapshot->curr_thread;
16194         heap->call_recursion_depth = snapshot->call_recursion_depth;
16195
16196         duk_pop_2(thr);
16197 }
16198
16199 /* XXX: better place for this */
16200 DUK_EXTERNAL void duk_set_global_object(duk_hthread *thr) {
16201         duk_hobject *h_glob;
16202         duk_hobject *h_prev_glob;
16203         duk_hobjenv *h_env;
16204         duk_hobject *h_prev_env;
16205
16206         DUK_ASSERT_API_ENTRY(thr);
16207
16208         DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(thr, -1)));
16209
16210         h_glob = duk_require_hobject(thr, -1);
16211         DUK_ASSERT(h_glob != NULL);
16212
16213         /*
16214          *  Replace global object.
16215          */
16216
16217         h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
16218         DUK_UNREF(h_prev_glob);
16219         thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
16220         DUK_HOBJECT_INCREF(thr, h_glob);
16221         DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob);  /* side effects, in theory (referenced by global env) */
16222
16223         /*
16224          *  Replace lexical environment for global scope
16225          *
16226          *  Create a new object environment for the global lexical scope.
16227          *  We can't just reset the _Target property of the current one,
16228          *  because the lexical scope is shared by other threads with the
16229          *  same (initial) built-ins.
16230          */
16231
16232         h_env = duk_hobjenv_alloc(thr,
16233                                   DUK_HOBJECT_FLAG_EXTENSIBLE |
16234                                   DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
16235         DUK_ASSERT(h_env != NULL);
16236         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_env) == NULL);
16237
16238         DUK_ASSERT(h_env->target == NULL);
16239         DUK_ASSERT(h_glob != NULL);
16240         h_env->target = h_glob;
16241         DUK_HOBJECT_INCREF(thr, h_glob);
16242         DUK_ASSERT(h_env->has_this == 0);
16243
16244         /* [ ... new_glob ] */
16245
16246         h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
16247         thr->builtins[DUK_BIDX_GLOBAL_ENV] = (duk_hobject *) h_env;
16248         DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_env);
16249         DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env);  /* side effects */
16250         DUK_UNREF(h_env);  /* without refcounts */
16251         DUK_UNREF(h_prev_env);
16252
16253         /* [ ... new_glob ] */
16254
16255         duk_pop(thr);
16256
16257         /* [ ... ] */
16258 }
16259 #line 1 "duk_api_inspect.c"
16260 /*
16261  *  Inspection
16262  */
16263
16264 /* #include duk_internal.h -> already included */
16265
16266 /* For footprint efficient multiple value setting: arrays are much better than
16267  * varargs, format string with parsing is often better than string pointer arrays.
16268  */
16269 DUK_LOCAL void duk__inspect_multiple_uint(duk_hthread *thr, const char *fmt, duk_int_t *vals) {
16270         duk_int_t val;
16271         const char *p;
16272         const char *p_curr;
16273         duk_size_t len;
16274
16275         for (p = fmt;;) {
16276                 len = DUK_STRLEN(p);
16277                 p_curr = p;
16278                 p += len + 1;
16279                 if (len == 0) {
16280                         /* Double NUL (= empty key) terminates. */
16281                         break;
16282                 }
16283                 val = *vals++;
16284                 if (val >= 0) {
16285                         /* Negative values are markers to skip key. */
16286                         duk_push_string(thr, p_curr);
16287                         duk_push_int(thr, val);
16288                         duk_put_prop(thr, -3);
16289                 }
16290         }
16291 }
16292
16293 /* Raw helper to extract internal information / statistics about a value.
16294  * The return value is an object with properties that are version specific.
16295  * The properties must not expose anything that would lead to security
16296  * issues (e.g. exposing compiled function 'data' buffer might be an issue).
16297  * Currently only counts and sizes and such are given so there shouldn't
16298  * be security implications.
16299  */
16300
16301 #define DUK__IDX_TYPE     0
16302 #define DUK__IDX_ITAG     1
16303 #define DUK__IDX_REFC     2
16304 #define DUK__IDX_HBYTES   3
16305 #define DUK__IDX_CLASS    4
16306 #define DUK__IDX_PBYTES   5
16307 #define DUK__IDX_ESIZE    6
16308 #define DUK__IDX_ENEXT    7
16309 #define DUK__IDX_ASIZE    8
16310 #define DUK__IDX_HSIZE    9
16311 #define DUK__IDX_BCBYTES  10
16312 #define DUK__IDX_DBYTES   11
16313 #define DUK__IDX_TSTATE   12
16314 #define DUK__IDX_VARIANT  13
16315
16316 DUK_EXTERNAL void duk_inspect_value(duk_hthread *thr, duk_idx_t idx) {
16317         duk_tval *tv;
16318         duk_heaphdr *h;
16319         /* The temporary values should be in an array rather than individual
16320          * variables which (in practice) ensures that the compiler won't map
16321          * them to registers and emit a lot of unnecessary shuffling code.
16322          */
16323         duk_int_t vals[14];
16324
16325         DUK_ASSERT_API_ENTRY(thr);
16326
16327         /* Assume two's complement and set everything to -1. */
16328         duk_memset((void *) &vals, (int) 0xff, sizeof(vals));
16329         DUK_ASSERT(vals[DUK__IDX_TYPE] == -1);  /* spot check one */
16330
16331         tv = duk_get_tval_or_unused(thr, idx);
16332         h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL);
16333
16334         vals[DUK__IDX_TYPE] = duk_get_type_tval(tv);
16335         vals[DUK__IDX_ITAG] = (duk_int_t) DUK_TVAL_GET_TAG(tv);
16336
16337         duk_push_bare_object(thr);  /* Invalidates 'tv'. */
16338         tv = NULL;
16339
16340         if (h == NULL) {
16341                 goto finish;
16342         }
16343         duk_push_pointer(thr, (void *) h);
16344         duk_put_prop_literal(thr, -2, "hptr");
16345
16346 #if 0
16347         /* Covers a lot of information, e.g. buffer and string variants. */
16348         duk_push_uint(thr, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
16349         duk_put_prop_literal(thr, -2, "hflags");
16350 #endif
16351
16352 #if defined(DUK_USE_REFERENCE_COUNTING)
16353         vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h);
16354 #endif
16355         vals[DUK__IDX_VARIANT] = 0;
16356
16357         /* Heaphdr size and additional allocation size, followed by
16358          * type specific stuff (with varying value count).
16359          */
16360         switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
16361         case DUK_HTYPE_STRING: {
16362                 duk_hstring *h_str = (duk_hstring *) h;
16363                 vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1);
16364 #if defined(DUK_USE_HSTRING_EXTDATA)
16365                 if (DUK_HSTRING_HAS_EXTDATA(h_str)) {
16366                         vals[DUK__IDX_VARIANT] = 1;
16367                 }
16368 #endif
16369                 break;
16370         }
16371         case DUK_HTYPE_OBJECT: {
16372                 duk_hobject *h_obj = (duk_hobject *) h;
16373
16374                 /* XXX: variants here are maybe pointless; class is enough? */
16375                 if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
16376                         vals[DUK__IDX_HBYTES] = sizeof(duk_harray);
16377                 } else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
16378                         vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc);
16379                 } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
16380                         vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc);
16381                 } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
16382                         vals[DUK__IDX_HBYTES] = sizeof(duk_hthread);
16383                         vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state;
16384 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
16385                 } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
16386                         vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj);
16387                         /* XXX: some size information */
16388 #endif
16389                 } else {
16390                         vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject);
16391                 }
16392
16393                 vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
16394                 vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj);
16395                 vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj);
16396                 vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj);
16397                 vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj);
16398                 vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj);
16399
16400                 /* Note: e_next indicates the number of gc-reachable entries
16401                  * in the entry part, and also indicates the index where the
16402                  * next new property would be inserted.  It does *not* indicate
16403                  * the number of non-NULL keys present in the object.  That
16404                  * value could be counted separately but requires a pass through
16405                  * the key list.
16406                  */
16407
16408                 if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
16409                         duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj);
16410                         vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0);
16411                 }
16412                 break;
16413         }
16414         case DUK_HTYPE_BUFFER: {
16415                 duk_hbuffer *h_buf = (duk_hbuffer *) h;
16416
16417                 if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
16418                         if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
16419                                 vals[DUK__IDX_VARIANT] = 2;  /* buffer variant 2: external */
16420                                 vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external));
16421                         } else {
16422                                 /* When alloc_size == 0 the second allocation may not
16423                                  * actually exist.
16424                                  */
16425                                 vals[DUK__IDX_VARIANT] = 1;  /* buffer variant 1: dynamic */
16426                                 vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic));
16427                         }
16428                         vals[DUK__IDX_DBYTES] = (duk_int_t) (DUK_HBUFFER_GET_SIZE(h_buf));
16429                 } else {
16430                         DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0);  /* buffer variant 0: fixed */
16431                         vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf));
16432                 }
16433                 break;
16434         }
16435         }
16436
16437  finish:
16438         duk__inspect_multiple_uint(thr,
16439             "type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00"
16440             "pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00"
16441             "bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00",
16442             (duk_int_t *) &vals);
16443 }
16444
16445 DUK_EXTERNAL void duk_inspect_callstack_entry(duk_hthread *thr, duk_int_t level) {
16446         duk_activation *act;
16447         duk_uint_fast32_t pc;
16448         duk_uint_fast32_t line;
16449
16450         DUK_ASSERT_API_ENTRY(thr);
16451
16452         /* -1   = top callstack entry
16453          * -2   = caller of level -1
16454          * etc
16455          */
16456         act = duk_hthread_get_activation_for_level(thr, level);
16457         if (act == NULL) {
16458                 duk_push_undefined(thr);
16459                 return;
16460         }
16461         duk_push_bare_object(thr);
16462
16463         /* Relevant PC is just before current one because PC is
16464          * post-incremented.  This should match what error augment
16465          * code does.
16466          */
16467         pc = duk_hthread_get_act_prev_pc(thr, act);
16468
16469         duk_push_tval(thr, &act->tv_func);
16470
16471         duk_push_uint(thr, (duk_uint_t) pc);
16472         duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_PC);
16473
16474 #if defined(DUK_USE_PC2LINE)
16475         line = duk_hobject_pc2line_query(thr, -1, pc);
16476 #else
16477         line = 0;
16478 #endif
16479         duk_push_uint(thr, (duk_uint_t) line);
16480         duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_LINE_NUMBER);
16481
16482         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_LC_FUNCTION);
16483         /* Providing access to e.g. act->lex_env would be dangerous: these
16484          * internal structures must never be accessible to the application.
16485          * Duktape relies on them having consistent data, and this consistency
16486          * is only asserted for, not checked for.
16487          */
16488 }
16489
16490 /* automatic undefs */
16491 #undef DUK__IDX_ASIZE
16492 #undef DUK__IDX_BCBYTES
16493 #undef DUK__IDX_CLASS
16494 #undef DUK__IDX_DBYTES
16495 #undef DUK__IDX_ENEXT
16496 #undef DUK__IDX_ESIZE
16497 #undef DUK__IDX_HBYTES
16498 #undef DUK__IDX_HSIZE
16499 #undef DUK__IDX_ITAG
16500 #undef DUK__IDX_PBYTES
16501 #undef DUK__IDX_REFC
16502 #undef DUK__IDX_TSTATE
16503 #undef DUK__IDX_TYPE
16504 #undef DUK__IDX_VARIANT
16505 #line 1 "duk_api_memory.c"
16506 /*
16507  *  Memory calls.
16508  */
16509
16510 /* #include duk_internal.h -> already included */
16511
16512 DUK_EXTERNAL void *duk_alloc_raw(duk_hthread *thr, duk_size_t size) {
16513         DUK_ASSERT_API_ENTRY(thr);
16514
16515         return DUK_ALLOC_RAW(thr->heap, size);
16516 }
16517
16518 DUK_EXTERNAL void duk_free_raw(duk_hthread *thr, void *ptr) {
16519         DUK_ASSERT_API_ENTRY(thr);
16520
16521         DUK_FREE_RAW(thr->heap, ptr);
16522 }
16523
16524 DUK_EXTERNAL void *duk_realloc_raw(duk_hthread *thr, void *ptr, duk_size_t size) {
16525         DUK_ASSERT_API_ENTRY(thr);
16526
16527         return DUK_REALLOC_RAW(thr->heap, ptr, size);
16528 }
16529
16530 DUK_EXTERNAL void *duk_alloc(duk_hthread *thr, duk_size_t size) {
16531         DUK_ASSERT_API_ENTRY(thr);
16532
16533         return DUK_ALLOC(thr->heap, size);
16534 }
16535
16536 DUK_EXTERNAL void duk_free(duk_hthread *thr, void *ptr) {
16537         DUK_ASSERT_API_ENTRY(thr);
16538
16539         DUK_FREE_CHECKED(thr, ptr);
16540 }
16541
16542 DUK_EXTERNAL void *duk_realloc(duk_hthread *thr, void *ptr, duk_size_t size) {
16543         DUK_ASSERT_API_ENTRY(thr);
16544
16545         /*
16546          *  Note: since this is an exposed API call, there should be
16547          *  no way a mark-and-sweep could have a side effect on the
16548          *  memory allocation behind 'ptr'; the pointer should never
16549          *  be something that Duktape wants to change.
16550          *
16551          *  Thus, no need to use DUK_REALLOC_INDIRECT (and we don't
16552          *  have the storage location here anyway).
16553          */
16554
16555         return DUK_REALLOC(thr->heap, ptr, size);
16556 }
16557
16558 DUK_EXTERNAL void duk_get_memory_functions(duk_hthread *thr, duk_memory_functions *out_funcs) {
16559         duk_heap *heap;
16560
16561         DUK_ASSERT_API_ENTRY(thr);
16562         DUK_ASSERT(out_funcs != NULL);
16563         DUK_ASSERT(thr != NULL);
16564         DUK_ASSERT(thr->heap != NULL);
16565
16566         heap = thr->heap;
16567         out_funcs->alloc_func = heap->alloc_func;
16568         out_funcs->realloc_func = heap->realloc_func;
16569         out_funcs->free_func = heap->free_func;
16570         out_funcs->udata = heap->heap_udata;
16571 }
16572
16573 DUK_EXTERNAL void duk_gc(duk_hthread *thr, duk_uint_t flags) {
16574         duk_heap *heap;
16575         duk_small_uint_t ms_flags;
16576
16577         DUK_ASSERT_API_ENTRY(thr);
16578         heap = thr->heap;
16579         DUK_ASSERT(heap != NULL);
16580
16581         DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
16582         DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY);  /* Compact flag is 1:1 with emergency flag which forces compaction. */
16583         ms_flags = (duk_small_uint_t) flags;
16584         duk_heap_mark_and_sweep(heap, ms_flags);
16585 }
16586 #line 1 "duk_api_object.c"
16587 /*
16588  *  Object handling: property access and other support functions.
16589  */
16590
16591 /* #include duk_internal.h -> already included */
16592
16593 /*
16594  *  Property handling
16595  *
16596  *  The API exposes only the most common property handling functions.
16597  *  The caller can invoke ECMAScript built-ins for full control (e.g.
16598  *  defineProperty, getOwnPropertyDescriptor).
16599  */
16600
16601 DUK_EXTERNAL duk_bool_t duk_get_prop(duk_hthread *thr, duk_idx_t obj_idx) {
16602         duk_tval *tv_obj;
16603         duk_tval *tv_key;
16604         duk_bool_t rc;
16605
16606         DUK_ASSERT_API_ENTRY(thr);
16607
16608         /* Note: copying tv_obj and tv_key to locals to shield against a valstack
16609          * resize is not necessary for a property get right now.
16610          */
16611
16612         tv_obj = duk_require_tval(thr, obj_idx);
16613         tv_key = duk_require_tval(thr, -1);
16614
16615         rc = duk_hobject_getprop(thr, tv_obj, tv_key);
16616         DUK_ASSERT(rc == 0 || rc == 1);
16617         /* a value is left on stack regardless of rc */
16618
16619         duk_remove_m2(thr);  /* remove key */
16620         DUK_ASSERT(duk_is_undefined(thr, -1) || rc == 1);
16621         return rc;  /* 1 if property found, 0 otherwise */
16622 }
16623
16624 DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
16625         DUK_ASSERT_API_ENTRY(thr);
16626         DUK_ASSERT(key != NULL);
16627
16628         obj_idx = duk_require_normalize_index(thr, obj_idx);
16629         (void) duk_push_string(thr, key);
16630         return duk_get_prop(thr, obj_idx);
16631 }
16632
16633 DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
16634         DUK_ASSERT_API_ENTRY(thr);
16635         DUK_ASSERT(key != NULL);
16636
16637         obj_idx = duk_require_normalize_index(thr, obj_idx);
16638         (void) duk_push_lstring(thr, key, key_len);
16639         return duk_get_prop(thr, obj_idx);
16640 }
16641
16642 #if !defined(DUK_USE_PREFER_SIZE)
16643 DUK_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) {
16644         DUK_ASSERT_API_ENTRY(thr);
16645         DUK_ASSERT(key != NULL);
16646         DUK_ASSERT(key[key_len] == (char) 0);
16647
16648         obj_idx = duk_require_normalize_index(thr, obj_idx);
16649         (void) duk_push_literal_raw(thr, key, key_len);
16650         return duk_get_prop(thr, obj_idx);
16651 }
16652 #endif
16653
16654 DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
16655         DUK_ASSERT_API_ENTRY(thr);
16656
16657         obj_idx = duk_require_normalize_index(thr, obj_idx);
16658         duk_push_uarridx(thr, arr_idx);
16659         return duk_get_prop(thr, obj_idx);
16660 }
16661
16662 DUK_EXTERNAL duk_bool_t duk_get_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
16663         DUK_ASSERT_API_ENTRY(thr);
16664
16665         obj_idx = duk_require_normalize_index(thr, obj_idx);
16666         (void) duk_push_heapptr(thr, ptr);  /* NULL -> 'undefined' */
16667         return duk_get_prop(thr, obj_idx);
16668 }
16669
16670 DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
16671         DUK_ASSERT_API_ENTRY(thr);
16672         DUK_ASSERT_STRIDX_VALID(stridx);
16673
16674         obj_idx = duk_require_normalize_index(thr, obj_idx);
16675         (void) duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
16676         return duk_get_prop(thr, obj_idx);
16677 }
16678
16679 DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
16680         return duk_get_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
16681                                         (duk_small_uint_t) (packed_args & 0xffffUL));
16682 }
16683
16684 DUK_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) {
16685         duk_bool_t rc;
16686
16687         DUK_ASSERT_API_ENTRY(thr);
16688         DUK_ASSERT_STRIDX_VALID(stridx);
16689
16690         rc = duk_get_prop_stridx(thr, obj_idx, stridx);
16691         if (out_has_prop) {
16692                 *out_has_prop = rc;
16693         }
16694         return duk_to_boolean_top_pop(thr);
16695 }
16696
16697 DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_hthread *thr, duk_idx_t obj_idx, duk_idx_t idx_key) {
16698         duk_tval *tv_obj;
16699         duk_tval *tv_key;
16700         duk_tval *tv_val;
16701         duk_bool_t throw_flag;
16702         duk_bool_t rc;
16703
16704         /* Note: copying tv_obj and tv_key to locals to shield against a valstack
16705          * resize is not necessary for a property put right now (putprop protects
16706          * against it internally).
16707          */
16708
16709         /* Key and value indices are either (-2, -1) or (-1, -2).  Given idx_key,
16710          * idx_val is always (idx_key ^ 0x01).
16711          */
16712         DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
16713                    (idx_key == -1 && (idx_key ^ 1) == -2));
16714         /* XXX: Direct access; faster validation. */
16715         tv_obj = duk_require_tval(thr, obj_idx);
16716         tv_key = duk_require_tval(thr, idx_key);
16717         tv_val = duk_require_tval(thr, idx_key ^ 1);
16718         throw_flag = duk_is_strict_call(thr);
16719
16720         rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
16721         DUK_ASSERT(rc == 0 || rc == 1);
16722
16723         duk_pop_2(thr);  /* remove key and value */
16724         return rc;  /* 1 if property found, 0 otherwise */
16725 }
16726
16727 DUK_EXTERNAL duk_bool_t duk_put_prop(duk_hthread *thr, duk_idx_t obj_idx) {
16728         DUK_ASSERT_API_ENTRY(thr);
16729         return duk__put_prop_shared(thr, obj_idx, -2);
16730 }
16731
16732 DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
16733         DUK_ASSERT_API_ENTRY(thr);
16734         DUK_ASSERT(key != NULL);
16735
16736         /* Careful here and with other duk_put_prop_xxx() helpers: the
16737          * target object and the property value may be in the same value
16738          * stack slot (unusual, but still conceptually clear).
16739          */
16740         obj_idx = duk_normalize_index(thr, obj_idx);
16741         (void) duk_push_string(thr, key);
16742         return duk__put_prop_shared(thr, obj_idx, -1);
16743 }
16744
16745 DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
16746         DUK_ASSERT_API_ENTRY(thr);
16747         DUK_ASSERT(key != NULL);
16748
16749         obj_idx = duk_normalize_index(thr, obj_idx);
16750         (void) duk_push_lstring(thr, key, key_len);
16751         return duk__put_prop_shared(thr, obj_idx, -1);
16752 }
16753
16754 #if !defined(DUK_USE_PREFER_SIZE)
16755 DUK_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) {
16756         DUK_ASSERT_API_ENTRY(thr);
16757         DUK_ASSERT(key != NULL);
16758         DUK_ASSERT(key[key_len] == (char) 0);
16759
16760         obj_idx = duk_normalize_index(thr, obj_idx);
16761         (void) duk_push_literal_raw(thr, key, key_len);
16762         return duk__put_prop_shared(thr, obj_idx, -1);
16763 }
16764 #endif
16765
16766 DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
16767         DUK_ASSERT_API_ENTRY(thr);
16768
16769         obj_idx = duk_require_normalize_index(thr, obj_idx);
16770         duk_push_uarridx(thr, arr_idx);
16771         return duk__put_prop_shared(thr, obj_idx, -1);
16772 }
16773
16774 DUK_EXTERNAL duk_bool_t duk_put_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
16775         DUK_ASSERT_API_ENTRY(thr);
16776
16777         obj_idx = duk_require_normalize_index(thr, obj_idx);
16778         (void) duk_push_heapptr(thr, ptr);  /* NULL -> 'undefined' */
16779         return duk__put_prop_shared(thr, obj_idx, -1);
16780 }
16781
16782
16783 DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
16784         DUK_ASSERT_API_ENTRY(thr);
16785         DUK_ASSERT_STRIDX_VALID(stridx);
16786
16787         obj_idx = duk_require_normalize_index(thr, obj_idx);
16788         duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
16789         return duk__put_prop_shared(thr, obj_idx, -1);
16790 }
16791
16792 DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
16793         return duk_put_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
16794                                         (duk_small_uint_t) (packed_args & 0xffffUL));
16795 }
16796
16797 DUK_EXTERNAL duk_bool_t duk_del_prop(duk_hthread *thr, duk_idx_t obj_idx) {
16798         duk_tval *tv_obj;
16799         duk_tval *tv_key;
16800         duk_bool_t throw_flag;
16801         duk_bool_t rc;
16802
16803         DUK_ASSERT_API_ENTRY(thr);
16804
16805         /* Note: copying tv_obj and tv_key to locals to shield against a valstack
16806          * resize is not necessary for a property delete right now.
16807          */
16808
16809         tv_obj = duk_require_tval(thr, obj_idx);
16810         tv_key = duk_require_tval(thr, -1);
16811         throw_flag = duk_is_strict_call(thr);
16812
16813         rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
16814         DUK_ASSERT(rc == 0 || rc == 1);
16815
16816         duk_pop(thr);  /* remove key */
16817         return rc;
16818 }
16819
16820 DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
16821         DUK_ASSERT_API_ENTRY(thr);
16822         DUK_ASSERT(key != NULL);
16823
16824         obj_idx = duk_require_normalize_index(thr, obj_idx);
16825         (void) duk_push_string(thr, key);
16826         return duk_del_prop(thr, obj_idx);
16827 }
16828
16829 DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
16830         DUK_ASSERT_API_ENTRY(thr);
16831         DUK_ASSERT(key != NULL);
16832
16833         obj_idx = duk_require_normalize_index(thr, obj_idx);
16834         (void) duk_push_lstring(thr, key, key_len);
16835         return duk_del_prop(thr, obj_idx);
16836 }
16837
16838 #if !defined(DUK_USE_PREFER_SIZE)
16839 DUK_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) {
16840         DUK_ASSERT_API_ENTRY(thr);
16841         DUK_ASSERT(key != NULL);
16842         DUK_ASSERT(key[key_len] == (char) 0);
16843
16844         obj_idx = duk_require_normalize_index(thr, obj_idx);
16845         (void) duk_push_literal_raw(thr, key, key_len);
16846         return duk_del_prop(thr, obj_idx);
16847 }
16848 #endif
16849
16850 DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
16851         DUK_ASSERT_API_ENTRY(thr);
16852
16853         obj_idx = duk_require_normalize_index(thr, obj_idx);
16854         duk_push_uarridx(thr, arr_idx);
16855         return duk_del_prop(thr, obj_idx);
16856 }
16857
16858 DUK_EXTERNAL duk_bool_t duk_del_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
16859         DUK_ASSERT_API_ENTRY(thr);
16860
16861         obj_idx = duk_require_normalize_index(thr, obj_idx);
16862         (void) duk_push_heapptr(thr, ptr);  /* NULL -> 'undefined' */
16863         return duk_del_prop(thr, obj_idx);
16864 }
16865
16866 DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
16867         DUK_ASSERT_API_ENTRY(thr);
16868         DUK_ASSERT_STRIDX_VALID(stridx);
16869
16870         obj_idx = duk_require_normalize_index(thr, obj_idx);
16871         duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
16872         return duk_del_prop(thr, obj_idx);
16873 }
16874
16875 #if 0
16876 DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
16877         return duk_del_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
16878                                         (duk_small_uint_t) (packed_args & 0xffffUL));
16879 }
16880 #endif
16881
16882 DUK_EXTERNAL duk_bool_t duk_has_prop(duk_hthread *thr, duk_idx_t obj_idx) {
16883         duk_tval *tv_obj;
16884         duk_tval *tv_key;
16885         duk_bool_t rc;
16886
16887         DUK_ASSERT_API_ENTRY(thr);
16888
16889         /* Note: copying tv_obj and tv_key to locals to shield against a valstack
16890          * resize is not necessary for a property existence check right now.
16891          */
16892
16893         tv_obj = duk_require_tval(thr, obj_idx);
16894         tv_key = duk_require_tval(thr, -1);
16895
16896         rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
16897         DUK_ASSERT(rc == 0 || rc == 1);
16898
16899         duk_pop(thr);  /* remove key */
16900         return rc;  /* 1 if property found, 0 otherwise */
16901 }
16902
16903 DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_hthread *thr, duk_idx_t obj_idx, const char *key) {
16904         DUK_ASSERT_API_ENTRY(thr);
16905         DUK_ASSERT(key != NULL);
16906
16907         obj_idx = duk_require_normalize_index(thr, obj_idx);
16908         (void) duk_push_string(thr, key);
16909         return duk_has_prop(thr, obj_idx);
16910 }
16911
16912 DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_hthread *thr, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
16913         DUK_ASSERT_API_ENTRY(thr);
16914         DUK_ASSERT(key != NULL);
16915
16916         obj_idx = duk_require_normalize_index(thr, obj_idx);
16917         (void) duk_push_lstring(thr, key, key_len);
16918         return duk_has_prop(thr, obj_idx);
16919 }
16920
16921 #if !defined(DUK_USE_PREFER_SIZE)
16922 DUK_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) {
16923         DUK_ASSERT_API_ENTRY(thr);
16924         DUK_ASSERT(key != NULL);
16925         DUK_ASSERT(key[key_len] == (char) 0);
16926
16927         obj_idx = duk_require_normalize_index(thr, obj_idx);
16928         (void) duk_push_literal_raw(thr, key, key_len);
16929         return duk_has_prop(thr, obj_idx);
16930 }
16931 #endif
16932
16933 DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_hthread *thr, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
16934         DUK_ASSERT_API_ENTRY(thr);
16935
16936         obj_idx = duk_require_normalize_index(thr, obj_idx);
16937         duk_push_uarridx(thr, arr_idx);
16938         return duk_has_prop(thr, obj_idx);
16939 }
16940
16941 DUK_EXTERNAL duk_bool_t duk_has_prop_heapptr(duk_hthread *thr, duk_idx_t obj_idx, void *ptr) {
16942         DUK_ASSERT_API_ENTRY(thr);
16943
16944         obj_idx = duk_require_normalize_index(thr, obj_idx);
16945         (void) duk_push_heapptr(thr, ptr);  /* NULL -> 'undefined' */
16946         return duk_has_prop(thr, obj_idx);
16947 }
16948
16949 DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
16950         DUK_ASSERT_API_ENTRY(thr);
16951         DUK_ASSERT_STRIDX_VALID(stridx);
16952
16953         obj_idx = duk_require_normalize_index(thr, obj_idx);
16954         duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
16955         return duk_has_prop(thr, obj_idx);
16956 }
16957
16958 #if 0
16959 DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
16960         return duk_has_prop_stridx(thr, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
16961                                         (duk_small_uint_t) (packed_args & 0xffffUL));
16962 }
16963 #endif
16964
16965 /* Define own property without inheritance lookups and such.  This differs from
16966  * [[DefineOwnProperty]] because special behaviors (like Array 'length') are
16967  * not invoked by this method.  The caller must be careful to invoke any such
16968  * behaviors if necessary.
16969  */
16970 DUK_INTERNAL void duk_xdef_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t desc_flags) {
16971         duk_hobject *obj;
16972         duk_hstring *key;
16973
16974         DUK_ASSERT_API_ENTRY(thr);
16975
16976         obj = duk_require_hobject(thr, obj_idx);
16977         DUK_ASSERT(obj != NULL);
16978         key = duk_to_property_key_hstring(thr, -2);
16979         DUK_ASSERT(key != NULL);
16980         DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
16981
16982         duk_hobject_define_property_internal(thr, obj, key, desc_flags);
16983
16984         duk_pop(thr);  /* pop key */
16985 }
16986
16987 DUK_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) {
16988         duk_hobject *obj;
16989
16990         DUK_ASSERT_API_ENTRY(thr);
16991
16992         obj = duk_require_hobject(thr, obj_idx);
16993         DUK_ASSERT(obj != NULL);
16994
16995         duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags);
16996         /* value popped by call */
16997 }
16998
16999 DUK_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) {
17000         duk_hobject *obj;
17001         duk_hstring *key;
17002
17003         DUK_ASSERT_API_ENTRY(thr);
17004         DUK_ASSERT_STRIDX_VALID(stridx);
17005
17006         obj = duk_require_hobject(thr, obj_idx);
17007         DUK_ASSERT(obj != NULL);
17008         key = DUK_HTHREAD_GET_STRING(thr, stridx);
17009         DUK_ASSERT(key != NULL);
17010         DUK_ASSERT(duk_require_tval(thr, -1) != NULL);
17011
17012         duk_hobject_define_property_internal(thr, obj, key, desc_flags);
17013         /* value popped by call */
17014 }
17015
17016 DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_hthread *thr, duk_uint_t packed_args) {
17017         duk_xdef_prop_stridx(thr, (duk_idx_t) (duk_int8_t) (packed_args >> 24),
17018                                   (duk_small_uint_t) (packed_args >> 8) & 0xffffUL,
17019                                   (duk_small_uint_t) (packed_args & 0xffL));
17020 }
17021
17022 #if 0  /*unused*/
17023 DUK_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) {
17024         duk_hobject *obj;
17025         duk_hstring *key;
17026
17027         DUK_ASSERT_API_ENTRY(thr);
17028         DUK_ASSERT_STRIDX_VALID(stridx);
17029         DUK_ASSERT_BIDX_VALID(builtin_idx);
17030
17031         obj = duk_require_hobject(thr, obj_idx);
17032         DUK_ASSERT(obj != NULL);
17033         key = DUK_HTHREAD_GET_STRING(thr, stridx);
17034         DUK_ASSERT(key != NULL);
17035
17036         duk_push_hobject(thr, thr->builtins[builtin_idx]);
17037         duk_hobject_define_property_internal(thr, obj, key, desc_flags);
17038         /* value popped by call */
17039 }
17040 #endif
17041
17042 /* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
17043  * setter/getter into an object property.  This is needed by the 'arguments'
17044  * object creation code, function instance creation code, and Function.prototype.bind().
17045  */
17046
17047 DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_hthread *thr, duk_idx_t obj_idx, duk_small_uint_t stridx) {
17048         DUK_ASSERT_API_ENTRY(thr);
17049
17050         obj_idx = duk_require_normalize_index(thr, obj_idx);
17051         duk_push_hstring_stridx(thr, stridx);
17052         duk_push_hobject_bidx(thr, DUK_BIDX_TYPE_ERROR_THROWER);
17053         duk_dup_top(thr);
17054         duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE);  /* attributes always 0 */
17055 }
17056
17057 /* Object.getOwnPropertyDescriptor() equivalent C binding. */
17058 DUK_EXTERNAL void duk_get_prop_desc(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
17059         DUK_ASSERT_API_ENTRY(thr);
17060         DUK_UNREF(flags);  /* no flags defined yet */
17061
17062         duk_hobject_object_get_own_property_descriptor(thr, obj_idx);  /* [ ... key ] -> [ ... desc ] */
17063 }
17064
17065 /* Object.defineProperty() equivalent C binding. */
17066 DUK_EXTERNAL void duk_def_prop(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t flags) {
17067         duk_idx_t idx_base;
17068         duk_hobject *obj;
17069         duk_hstring *key;
17070         duk_idx_t idx_value;
17071         duk_hobject *get;
17072         duk_hobject *set;
17073         duk_uint_t is_data_desc;
17074         duk_uint_t is_acc_desc;
17075
17076         DUK_ASSERT_API_ENTRY(thr);
17077
17078         obj = duk_require_hobject(thr, obj_idx);
17079
17080         is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
17081         is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
17082         if (is_data_desc && is_acc_desc) {
17083                 /* "Have" flags must not be conflicting so that they would
17084                  * apply to both a plain property and an accessor at the same
17085                  * time.
17086                  */
17087                 goto fail_invalid_desc;
17088         }
17089
17090         idx_base = duk_get_top_index(thr);
17091         if (flags & DUK_DEFPROP_HAVE_SETTER) {
17092                 duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
17093                                                      DUK_TYPE_MASK_OBJECT |
17094                                                      DUK_TYPE_MASK_LIGHTFUNC);
17095                 set = duk_get_hobject_promote_lfunc(thr, idx_base);
17096                 if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
17097                         goto fail_not_callable;
17098                 }
17099                 idx_base--;
17100         } else {
17101                 set = NULL;
17102         }
17103         if (flags & DUK_DEFPROP_HAVE_GETTER) {
17104                 duk_require_type_mask(thr, idx_base, DUK_TYPE_MASK_UNDEFINED |
17105                                                      DUK_TYPE_MASK_OBJECT |
17106                                                      DUK_TYPE_MASK_LIGHTFUNC);
17107                 get = duk_get_hobject_promote_lfunc(thr, idx_base);
17108                 if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
17109                         goto fail_not_callable;
17110                 }
17111                 idx_base--;
17112         } else {
17113                 get = NULL;
17114         }
17115         if (flags & DUK_DEFPROP_HAVE_VALUE) {
17116                 idx_value = idx_base;
17117                 idx_base--;
17118         } else {
17119                 idx_value = (duk_idx_t) -1;
17120         }
17121         key = duk_to_property_key_hstring(thr, idx_base);
17122         DUK_ASSERT(key != NULL);
17123
17124         duk_require_valid_index(thr, idx_base);
17125
17126         duk_hobject_define_property_helper(thr,
17127                                            flags /*defprop_flags*/,
17128                                            obj,
17129                                            key,
17130                                            idx_value,
17131                                            get,
17132                                            set,
17133                                            1 /*throw_flag*/);
17134
17135         /* Clean up stack */
17136
17137         duk_set_top(thr, idx_base);
17138
17139         /* [ ... obj ... ] */
17140
17141         return;
17142
17143  fail_invalid_desc:
17144         DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
17145         DUK_WO_NORETURN(return;);
17146
17147  fail_not_callable:
17148         DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
17149         DUK_WO_NORETURN(return;);
17150 }
17151
17152 /*
17153  *  Object related
17154  *
17155  *  Note: seal() and freeze() are accessible through ECMAScript bindings,
17156  *  and are not exposed through the API.
17157  */
17158
17159 DUK_EXTERNAL void duk_compact(duk_hthread *thr, duk_idx_t obj_idx) {
17160         duk_hobject *obj;
17161
17162         DUK_ASSERT_API_ENTRY(thr);
17163
17164         obj = duk_get_hobject(thr, obj_idx);
17165         if (obj) {
17166                 /* Note: this may fail, caller should protect the call if necessary */
17167                 duk_hobject_compact_props(thr, obj);
17168         }
17169 }
17170
17171 DUK_INTERNAL void duk_compact_m1(duk_hthread *thr) {
17172         DUK_ASSERT_API_ENTRY(thr);
17173
17174         duk_compact(thr, -1);
17175 }
17176
17177 /* XXX: the duk_hobject_enum.c stack APIs should be reworked */
17178
17179 DUK_EXTERNAL void duk_enum(duk_hthread *thr, duk_idx_t obj_idx, duk_uint_t enum_flags) {
17180         DUK_ASSERT_API_ENTRY(thr);
17181
17182         duk_dup(thr, obj_idx);
17183         duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
17184         duk_hobject_enumerator_create(thr, enum_flags);   /* [target] -> [enum] */
17185 }
17186
17187 DUK_EXTERNAL duk_bool_t duk_next(duk_hthread *thr, duk_idx_t enum_index, duk_bool_t get_value) {
17188         DUK_ASSERT_API_ENTRY(thr);
17189
17190         duk_require_hobject(thr, enum_index);
17191         duk_dup(thr, enum_index);
17192         return duk_hobject_enumerator_next(thr, get_value);
17193 }
17194
17195 DUK_INTERNAL void duk_seal_freeze_raw(duk_hthread *thr, duk_idx_t obj_idx, duk_bool_t is_freeze) {
17196         duk_tval *tv;
17197         duk_hobject *h;
17198
17199         DUK_ASSERT_API_ENTRY(thr);
17200
17201         tv = duk_require_tval(thr, obj_idx);
17202         DUK_ASSERT(tv != NULL);
17203
17204         /* Seal/freeze are quite rare in practice so it'd be nice to get the
17205          * correct behavior simply via automatic promotion (at the cost of some
17206          * memory churn).  However, the promoted objects don't behave the same,
17207          * e.g. promoted lightfuncs are extensible.
17208          */
17209
17210         switch (DUK_TVAL_GET_TAG(tv)) {
17211         case DUK_TAG_BUFFER:
17212                 /* Plain buffer: already sealed, but not frozen (and can't be frozen
17213                  * because index properties can't be made non-writable.
17214                  */
17215                 if (is_freeze) {
17216                         goto fail_cannot_freeze;
17217                 }
17218                 break;
17219         case DUK_TAG_LIGHTFUNC:
17220                 /* Lightfunc: already sealed and frozen, success. */
17221                 break;
17222         case DUK_TAG_OBJECT:
17223                 h = DUK_TVAL_GET_OBJECT(tv);
17224                 DUK_ASSERT(h != NULL);
17225                 if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) {
17226                         /* Buffer objects cannot be frozen because there's no internal
17227                          * support for making virtual array indices non-writable.
17228                          */
17229                         DUK_DD(DUK_DDPRINT("cannot freeze a buffer object"));
17230                         goto fail_cannot_freeze;
17231                 }
17232                 duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
17233
17234                 /* Sealed and frozen objects cannot gain any more properties,
17235                  * so this is a good time to compact them.
17236                  */
17237                 duk_hobject_compact_props(thr, h);
17238                 break;
17239         default:
17240                 /* ES2015 Sections 19.1.2.5, 19.1.2.17 */
17241                 break;
17242         }
17243         return;
17244
17245  fail_cannot_freeze:
17246         DUK_ERROR_TYPE_INVALID_ARGS(thr);  /* XXX: proper error message */
17247         DUK_WO_NORETURN(return;);
17248 }
17249
17250 DUK_EXTERNAL void duk_seal(duk_hthread *thr, duk_idx_t obj_idx) {
17251         DUK_ASSERT_API_ENTRY(thr);
17252
17253         duk_seal_freeze_raw(thr, obj_idx, 0 /*is_freeze*/);
17254 }
17255
17256 DUK_EXTERNAL void duk_freeze(duk_hthread *thr, duk_idx_t obj_idx) {
17257         DUK_ASSERT_API_ENTRY(thr);
17258
17259         duk_seal_freeze_raw(thr, obj_idx, 1 /*is_freeze*/);
17260 }
17261
17262 /*
17263  *  Helpers for writing multiple properties
17264  */
17265
17266 DUK_EXTERNAL void duk_put_function_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_function_list_entry *funcs) {
17267         const duk_function_list_entry *ent = funcs;
17268
17269         DUK_ASSERT_API_ENTRY(thr);
17270
17271         obj_idx = duk_require_normalize_index(thr, obj_idx);
17272         if (ent != NULL) {
17273                 while (ent->key != NULL) {
17274                         duk_push_c_function(thr, ent->value, ent->nargs);
17275                         duk_put_prop_string(thr, obj_idx, ent->key);
17276                         ent++;
17277                 }
17278         }
17279 }
17280
17281 DUK_EXTERNAL void duk_put_number_list(duk_hthread *thr, duk_idx_t obj_idx, const duk_number_list_entry *numbers) {
17282         const duk_number_list_entry *ent = numbers;
17283         duk_tval *tv;
17284
17285         DUK_ASSERT_API_ENTRY(thr);
17286
17287         obj_idx = duk_require_normalize_index(thr, obj_idx);
17288         if (ent != NULL) {
17289                 while (ent->key != NULL) {
17290                         tv = thr->valstack_top++;
17291                         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));  /* value stack init policy */
17292                         DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value);  /* no need for decref/incref */
17293                         duk_put_prop_string(thr, obj_idx, ent->key);
17294                         ent++;
17295                 }
17296         }
17297 }
17298
17299 /*
17300  *  Shortcut for accessing global object properties
17301  */
17302
17303 DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_hthread *thr, const char *key) {
17304         duk_bool_t ret;
17305
17306         DUK_ASSERT_API_ENTRY(thr);
17307         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17308
17309         /* XXX: direct implementation */
17310
17311         duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17312         ret = duk_get_prop_string(thr, -1, key);
17313         duk_remove_m2(thr);
17314         return ret;
17315 }
17316
17317 DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
17318         duk_bool_t ret;
17319
17320         DUK_ASSERT_API_ENTRY(thr);
17321         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17322
17323         /* XXX: direct implementation */
17324
17325         duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17326         ret = duk_get_prop_lstring(thr, -1, key, key_len);
17327         duk_remove_m2(thr);
17328         return ret;
17329 }
17330
17331 #if !defined(DUK_USE_PREFER_SIZE)
17332 DUK_EXTERNAL duk_bool_t duk_get_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) {
17333         duk_bool_t ret;
17334
17335         DUK_ASSERT_API_ENTRY(thr);
17336         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17337         DUK_ASSERT(key[key_len] == (char) 0);
17338
17339         /* XXX: direct implementation */
17340
17341         duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17342         ret = duk_get_prop_literal_raw(thr, -1, key, key_len);
17343         duk_remove_m2(thr);
17344         return ret;
17345 }
17346 #endif
17347
17348 DUK_EXTERNAL duk_bool_t duk_get_global_heapptr(duk_hthread *thr, void *ptr) {
17349         duk_bool_t ret;
17350
17351         DUK_ASSERT_API_ENTRY(thr);
17352         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17353
17354         /* XXX: direct implementation */
17355
17356         duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17357         ret = duk_get_prop_heapptr(thr, -1, ptr);
17358         duk_remove_m2(thr);
17359         return ret;
17360 }
17361
17362
17363 DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_hthread *thr, const char *key) {
17364         duk_bool_t ret;
17365
17366         DUK_ASSERT_API_ENTRY(thr);
17367         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17368
17369         /* XXX: direct implementation */
17370
17371         duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17372         duk_insert(thr, -2);
17373         ret = duk_put_prop_string(thr, -2, key);  /* [ ... global val ] -> [ ... global ] */
17374         duk_pop(thr);
17375         return ret;
17376 }
17377
17378 DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_hthread *thr, const char *key, duk_size_t key_len) {
17379         duk_bool_t ret;
17380
17381         DUK_ASSERT_API_ENTRY(thr);
17382         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17383
17384         /* XXX: direct implementation */
17385
17386         duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17387         duk_insert(thr, -2);
17388         ret = duk_put_prop_lstring(thr, -2, key, key_len);  /* [ ... global val ] -> [ ... global ] */
17389         duk_pop(thr);
17390         return ret;
17391 }
17392
17393 #if !defined(DUK_USE_PREFER_SIZE)
17394 DUK_EXTERNAL duk_bool_t duk_put_global_literal_raw(duk_hthread *thr, const char *key, duk_size_t key_len) {
17395         duk_bool_t ret;
17396
17397         DUK_ASSERT_API_ENTRY(thr);
17398         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17399         DUK_ASSERT(key[key_len] == (char) 0);
17400
17401         /* XXX: direct implementation */
17402
17403         duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17404         duk_insert(thr, -2);
17405         ret = duk_put_prop_literal_raw(thr, -2, key, key_len);  /* [ ... global val ] -> [ ... global ] */
17406         duk_pop(thr);
17407         return ret;
17408 }
17409 #endif
17410
17411 DUK_EXTERNAL duk_bool_t duk_put_global_heapptr(duk_hthread *thr, void *ptr) {
17412         duk_bool_t ret;
17413
17414         DUK_ASSERT_API_ENTRY(thr);
17415         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
17416
17417         /* XXX: direct implementation */
17418
17419         duk_push_hobject(thr, thr->builtins[DUK_BIDX_GLOBAL]);
17420         duk_insert(thr, -2);
17421         ret = duk_put_prop_heapptr(thr, -2, ptr);  /* [ ... global val ] -> [ ... global ] */
17422         duk_pop(thr);
17423         return ret;
17424 }
17425
17426 /*
17427  *  ES2015 GetMethod()
17428  */
17429
17430 DUK_INTERNAL duk_bool_t duk_get_method_stridx(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t stridx) {
17431         (void) duk_get_prop_stridx(thr, idx, stridx);
17432         if (duk_is_null_or_undefined(thr, -1)) {
17433                 duk_pop_nodecref_unsafe(thr);
17434                 return 0;
17435         }
17436         if (!duk_is_callable(thr, -1)) {
17437                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
17438                 DUK_WO_NORETURN(return 0;);
17439         }
17440         return 1;
17441 }
17442
17443 /*
17444  *  Object prototype
17445  */
17446
17447 DUK_EXTERNAL void duk_get_prototype(duk_hthread *thr, duk_idx_t idx) {
17448         duk_hobject *obj;
17449         duk_hobject *proto;
17450
17451         DUK_ASSERT_API_ENTRY(thr);
17452
17453         obj = duk_require_hobject(thr, idx);
17454         DUK_ASSERT(obj != NULL);
17455
17456         /* XXX: shared helper for duk_push_hobject_or_undefined()? */
17457         proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
17458         if (proto) {
17459                 duk_push_hobject(thr, proto);
17460         } else {
17461                 duk_push_undefined(thr);
17462         }
17463 }
17464
17465 DUK_EXTERNAL void duk_set_prototype(duk_hthread *thr, duk_idx_t idx) {
17466         duk_hobject *obj;
17467         duk_hobject *proto;
17468
17469         DUK_ASSERT_API_ENTRY(thr);
17470
17471         obj = duk_require_hobject(thr, idx);
17472         DUK_ASSERT(obj != NULL);
17473         duk_require_type_mask(thr, -1, DUK_TYPE_MASK_UNDEFINED |
17474                                        DUK_TYPE_MASK_OBJECT);
17475         proto = duk_get_hobject(thr, -1);
17476         /* proto can also be NULL here (allowed explicitly) */
17477
17478 #if defined(DUK_USE_ROM_OBJECTS)
17479         if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
17480                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);  /* XXX: "read only object"? */
17481                 DUK_WO_NORETURN(return;);
17482         }
17483 #endif
17484
17485         DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
17486
17487         duk_pop(thr);
17488 }
17489
17490 /*
17491  *  Object finalizer
17492  */
17493
17494 #if defined(DUK_USE_FINALIZER_SUPPORT)
17495 /* XXX: these could be implemented as macros calling an internal function
17496  * directly.
17497  * XXX: same issue as with Duktape.fin: there's no way to delete the property
17498  * now (just set it to undefined).
17499  */
17500 DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
17501         DUK_ASSERT_API_ENTRY(thr);
17502
17503         duk_get_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
17504 }
17505
17506 DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
17507         duk_hobject *h;
17508         duk_bool_t callable;
17509
17510         DUK_ASSERT_API_ENTRY(thr);
17511
17512         h = duk_require_hobject(thr, idx);  /* Get before 'put' so that 'idx' is correct. */
17513         callable = duk_is_callable(thr, -1);
17514         duk_put_prop_stridx(thr, idx, DUK_STRIDX_INT_FINALIZER);
17515
17516         /* In addition to setting the finalizer property, keep a "have
17517          * finalizer" flag in duk_hobject in sync so that refzero can do
17518          * a very quick finalizer check by walking the prototype chain
17519          * and checking the flag alone.  (Note that this means that just
17520          * setting _Finalizer on an object won't affect finalizer checks.)
17521          *
17522          * NOTE: if the argument is a Proxy object, this flag will be set
17523          * on the Proxy, not the target.  As a result, the target won't get
17524          * a finalizer flag and the Proxy also won't be finalized as there's
17525          * an explicit Proxy check in finalization now.
17526          */
17527         if (callable) {
17528                 DUK_HOBJECT_SET_HAVE_FINALIZER(h);
17529         } else {
17530                 DUK_HOBJECT_CLEAR_HAVE_FINALIZER(h);
17531         }
17532 }
17533 #else  /* DUK_USE_FINALIZER_SUPPORT */
17534 DUK_EXTERNAL void duk_get_finalizer(duk_hthread *thr, duk_idx_t idx) {
17535         DUK_ASSERT_API_ENTRY(thr);
17536         DUK_UNREF(idx);
17537         DUK_ERROR_UNSUPPORTED(thr);
17538         DUK_WO_NORETURN(return;);
17539 }
17540
17541 DUK_EXTERNAL void duk_set_finalizer(duk_hthread *thr, duk_idx_t idx) {
17542         DUK_ASSERT_API_ENTRY(thr);
17543         DUK_UNREF(idx);
17544         DUK_ERROR_UNSUPPORTED(thr);
17545         DUK_WO_NORETURN(return;);
17546 }
17547 #endif  /* DUK_USE_FINALIZER_SUPPORT */
17548 #line 1 "duk_api_random.c"
17549 /*
17550  *  Random numbers
17551  */
17552
17553 /* #include duk_internal.h -> already included */
17554
17555 DUK_EXTERNAL duk_double_t duk_random(duk_hthread *thr) {
17556         return (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr);
17557 }
17558 #line 1 "duk_api_stack.c"
17559 /*
17560  *  API calls related to general value stack manipulation: resizing the value
17561  *  stack, pushing and popping values, type checking and reading values,
17562  *  coercing values, etc.
17563  *
17564  *  Also contains internal functions (such as duk_get_tval()), defined
17565  *  in duk_api_internal.h, with semantics similar to the public API.
17566  */
17567
17568 /* XXX: repetition of stack pre-checks -> helper or macro or inline */
17569 /* XXX: shared api error strings, and perhaps even throw code for rare cases? */
17570
17571 /* #include duk_internal.h -> already included */
17572
17573 /*
17574  *  Forward declarations
17575  */
17576
17577 DUK_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);
17578
17579 /*
17580  *  Global state for working around missing variadic macros
17581  */
17582
17583 #if !defined(DUK_USE_VARIADIC_MACROS)
17584 DUK_EXTERNAL const char *duk_api_global_filename = NULL;
17585 DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
17586 #endif
17587
17588 /*
17589  *  Misc helpers
17590  */
17591
17592 DUK_LOCAL const char * const duk__symbol_type_strings[4] = {
17593         "hidden", "global", "local", "wellknown"
17594 };
17595
17596 #if !defined(DUK_USE_PACKED_TVAL)
17597 DUK_LOCAL const duk_uint_t duk__type_from_tag[] = {
17598         DUK_TYPE_NUMBER,
17599         DUK_TYPE_NUMBER,  /* fastint */
17600         DUK_TYPE_UNDEFINED,
17601         DUK_TYPE_NULL,
17602         DUK_TYPE_BOOLEAN,
17603         DUK_TYPE_POINTER,
17604         DUK_TYPE_LIGHTFUNC,
17605         DUK_TYPE_NONE,
17606         DUK_TYPE_STRING,
17607         DUK_TYPE_OBJECT,
17608         DUK_TYPE_BUFFER,
17609 };
17610 DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = {
17611         DUK_TYPE_MASK_NUMBER,
17612         DUK_TYPE_MASK_NUMBER,  /* fastint */
17613         DUK_TYPE_MASK_UNDEFINED,
17614         DUK_TYPE_MASK_NULL,
17615         DUK_TYPE_MASK_BOOLEAN,
17616         DUK_TYPE_MASK_POINTER,
17617         DUK_TYPE_MASK_LIGHTFUNC,
17618         DUK_TYPE_MASK_NONE,
17619         DUK_TYPE_MASK_STRING,
17620         DUK_TYPE_MASK_OBJECT,
17621         DUK_TYPE_MASK_BUFFER,
17622 };
17623 #endif  /* !DUK_USE_PACKED_TVAL */
17624
17625 /* Assert that there's room for one value. */
17626 #define DUK__ASSERT_SPACE() do { \
17627                 DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
17628         } while (0)
17629
17630 /* Check that there's room to push one value. */
17631 #if defined(DUK_USE_VALSTACK_UNSAFE)
17632 /* Faster but value stack overruns are memory unsafe. */
17633 #define DUK__CHECK_SPACE() DUK__ASSERT_SPACE()
17634 #else
17635 #define DUK__CHECK_SPACE() do { \
17636                 if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
17637                         DUK_ERROR_RANGE_PUSH_BEYOND(thr); \
17638                 } \
17639         } while (0)
17640 #endif
17641
17642 DUK_LOCAL duk_small_uint_t duk__get_symbol_type(duk_hstring *h) {
17643         const duk_uint8_t *data;
17644         duk_size_t len;
17645
17646         DUK_ASSERT(h != NULL);
17647         DUK_ASSERT(DUK_HSTRING_HAS_SYMBOL(h));
17648         DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h) >= 1);  /* always true, symbol prefix */
17649
17650         data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
17651         len = DUK_HSTRING_GET_BYTELEN(h);
17652         DUK_ASSERT(len >= 1);
17653
17654         /* XXX: differentiate between 0x82 and 0xff (hidden vs. internal?)? */
17655
17656         if (data[0] == 0xffU) {
17657                 return DUK_SYMBOL_TYPE_HIDDEN;
17658         } else if (data[0] == 0x82U) {
17659                 return DUK_SYMBOL_TYPE_HIDDEN;
17660         } else if (data[0] == 0x80U) {
17661                 return DUK_SYMBOL_TYPE_GLOBAL;
17662         } else if (data[len - 1] != 0xffU) {
17663                 return DUK_SYMBOL_TYPE_LOCAL;
17664         } else {
17665                 return DUK_SYMBOL_TYPE_WELLKNOWN;
17666         }
17667 }
17668
17669 DUK_LOCAL const char *duk__get_symbol_type_string(duk_hstring *h) {
17670         duk_small_uint_t idx;
17671         idx = duk__get_symbol_type(h);
17672         DUK_ASSERT(idx < sizeof(duk__symbol_type_strings));
17673         return duk__symbol_type_strings[idx];
17674 }
17675
17676 DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag);
17677
17678 DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value, duk_bool_t require) {
17679         duk_tval *tv;
17680         duk_small_int_t c;
17681         duk_double_t d;
17682
17683         tv = duk_get_tval_or_unused(thr, idx);
17684         DUK_ASSERT(tv != NULL);
17685
17686         /*
17687          *  Special cases like NaN and +/- Infinity are handled explicitly
17688          *  because a plain C coercion from double to int handles these cases
17689          *  in undesirable ways.  For instance, NaN may coerce to INT_MIN
17690          *  (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX).
17691          *
17692          *  This double-to-int coercion differs from ToInteger() because it
17693          *  has a finite range (ToInteger() allows e.g. +/- Infinity).  It
17694          *  also differs from ToInt32() because the INT_MIN/INT_MAX clamping
17695          *  depends on the size of the int type on the platform.  In particular,
17696          *  on platforms with a 64-bit int type, the full range is allowed.
17697          */
17698
17699 #if defined(DUK_USE_FASTINT)
17700         if (DUK_TVAL_IS_FASTINT(tv)) {
17701                 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
17702 #if (DUK_INT_MAX <= 0x7fffffffL)
17703                 /* Clamping only necessary for 32-bit ints. */
17704                 if (t < DUK_INT_MIN) {
17705                         t = DUK_INT_MIN;
17706                 } else if (t > DUK_INT_MAX) {
17707                         t = DUK_INT_MAX;
17708                 }
17709 #endif
17710                 return (duk_int_t) t;
17711         }
17712 #endif
17713
17714         if (DUK_TVAL_IS_NUMBER(tv)) {
17715                 d = DUK_TVAL_GET_NUMBER(tv);
17716                 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
17717                 if (c == DUK_FP_NAN) {
17718                         return 0;
17719                 } else if (d < (duk_double_t) DUK_INT_MIN) {
17720                         /* covers -Infinity */
17721                         return DUK_INT_MIN;
17722                 } else if (d > (duk_double_t) DUK_INT_MAX) {
17723                         /* covers +Infinity */
17724                         return DUK_INT_MAX;
17725                 } else {
17726                         /* coerce towards zero */
17727                         return (duk_int_t) d;
17728                 }
17729         }
17730
17731         if (require) {
17732                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
17733                 DUK_WO_NORETURN(return 0;);
17734         }
17735
17736         return def_value;
17737 }
17738
17739 DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value, duk_bool_t require) {
17740         duk_tval *tv;
17741         duk_small_int_t c;
17742         duk_double_t d;
17743
17744         /* Same as above but for unsigned int range. */
17745
17746         tv = duk_get_tval_or_unused(thr, idx);
17747         DUK_ASSERT(tv != NULL);
17748
17749 #if defined(DUK_USE_FASTINT)
17750         if (DUK_TVAL_IS_FASTINT(tv)) {
17751                 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
17752                 if (t < 0) {
17753                         t = 0;
17754                 }
17755 #if (DUK_UINT_MAX <= 0xffffffffUL)
17756                 /* Clamping only necessary for 32-bit ints. */
17757                 else if (t > DUK_UINT_MAX) {
17758                         t = DUK_UINT_MAX;
17759                 }
17760 #endif
17761                 return (duk_uint_t) t;
17762         }
17763 #endif
17764
17765         if (DUK_TVAL_IS_NUMBER(tv)) {
17766                 d = DUK_TVAL_GET_NUMBER(tv);
17767                 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
17768                 if (c == DUK_FP_NAN) {
17769                         return 0;
17770                 } else if (d < 0.0) {
17771                         /* covers -Infinity */
17772                         return (duk_uint_t) 0;
17773                 } else if (d > (duk_double_t) DUK_UINT_MAX) {
17774                         /* covers +Infinity */
17775                         return (duk_uint_t) DUK_UINT_MAX;
17776                 } else {
17777                         /* coerce towards zero */
17778                         return (duk_uint_t) d;
17779                 }
17780         }
17781
17782         if (require) {
17783                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
17784                 DUK_WO_NORETURN(return 0;);
17785         }
17786
17787         return def_value;
17788 }
17789
17790 /*
17791  *  Stack index validation/normalization and getting a stack duk_tval ptr.
17792  *
17793  *  These are called by many API entrypoints so the implementations must be
17794  *  fast and "inlined".
17795  *
17796  *  There's some repetition because of this; keep the functions in sync.
17797  */
17798
17799 DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_hthread *thr, duk_idx_t idx) {
17800         duk_uidx_t vs_size;
17801         duk_uidx_t uidx;
17802
17803         DUK_ASSERT_API_ENTRY(thr);
17804         DUK_ASSERT(DUK_INVALID_INDEX < 0);
17805
17806         /* Care must be taken to avoid pointer wrapping in the index
17807          * validation.  For instance, on a 32-bit platform with 8-byte
17808          * duk_tval the index 0x20000000UL would wrap the memory space
17809          * once.
17810          */
17811
17812         /* Assume value stack sizes (in elements) fits into duk_idx_t. */
17813         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
17814         vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
17815         DUK_ASSERT_DISABLE(vs_size >= 0);  /* unsigned */
17816
17817         if (idx < 0) {
17818                 uidx = vs_size + (duk_uidx_t) idx;
17819         } else {
17820                 /* since index non-negative */
17821                 DUK_ASSERT(idx != DUK_INVALID_INDEX);
17822                 uidx = (duk_uidx_t) idx;
17823         }
17824
17825         /* DUK_INVALID_INDEX won't be accepted as a valid index. */
17826         DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
17827
17828         if (DUK_LIKELY(uidx < vs_size)) {
17829                 return (duk_idx_t) uidx;
17830         }
17831         return DUK_INVALID_INDEX;
17832 }
17833
17834 DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_hthread *thr, duk_idx_t idx) {
17835         duk_uidx_t vs_size;
17836         duk_uidx_t uidx;
17837
17838         DUK_ASSERT_API_ENTRY(thr);
17839         DUK_ASSERT(DUK_INVALID_INDEX < 0);
17840
17841         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
17842         vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
17843         DUK_ASSERT_DISABLE(vs_size >= 0);  /* unsigned */
17844
17845         if (idx < 0) {
17846                 uidx = vs_size + (duk_uidx_t) idx;
17847         } else {
17848                 DUK_ASSERT(idx != DUK_INVALID_INDEX);
17849                 uidx = (duk_uidx_t) idx;
17850         }
17851
17852         /* DUK_INVALID_INDEX won't be accepted as a valid index. */
17853         DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
17854
17855         if (DUK_LIKELY(uidx < vs_size)) {
17856                 return (duk_idx_t) uidx;
17857         }
17858         DUK_ERROR_RANGE_INDEX(thr, idx);
17859         DUK_WO_NORETURN(return 0;);
17860 }
17861
17862 DUK_INTERNAL duk_tval *duk_get_tval(duk_hthread *thr, duk_idx_t idx) {
17863         duk_uidx_t vs_size;
17864         duk_uidx_t uidx;
17865
17866         DUK_ASSERT_API_ENTRY(thr);
17867         DUK_ASSERT(DUK_INVALID_INDEX < 0);
17868
17869         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
17870         vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
17871         DUK_ASSERT_DISABLE(vs_size >= 0);  /* unsigned */
17872
17873         if (idx < 0) {
17874                 uidx = vs_size + (duk_uidx_t) idx;
17875         } else {
17876                 DUK_ASSERT(idx != DUK_INVALID_INDEX);
17877                 uidx = (duk_uidx_t) idx;
17878         }
17879
17880         /* DUK_INVALID_INDEX won't be accepted as a valid index. */
17881         DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
17882
17883         if (DUK_LIKELY(uidx < vs_size)) {
17884                 return thr->valstack_bottom + uidx;
17885         }
17886         return NULL;
17887 }
17888
17889 /* Variant of duk_get_tval() which is guaranteed to return a valid duk_tval
17890  * pointer.  When duk_get_tval() would return NULL, this variant returns a
17891  * pointer to a duk_tval with tag DUK_TAG_UNUSED.  This allows the call site
17892  * to avoid an unnecessary NULL check which sometimes leads to better code.
17893  * The return duk_tval is read only (at least for the UNUSED value).
17894  */
17895 DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER();
17896
17897 DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_hthread *thr, duk_idx_t idx) {
17898         duk_tval *tv;
17899
17900         DUK_ASSERT_API_ENTRY(thr);
17901
17902         tv = duk_get_tval(thr, idx);
17903         if (tv != NULL) {
17904                 return tv;
17905         }
17906         return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused);
17907 }
17908
17909 DUK_INTERNAL duk_tval *duk_require_tval(duk_hthread *thr, duk_idx_t idx) {
17910         duk_uidx_t vs_size;
17911         duk_uidx_t uidx;
17912
17913         DUK_ASSERT_API_ENTRY(thr);
17914         DUK_ASSERT(DUK_INVALID_INDEX < 0);
17915
17916         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
17917         vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
17918         DUK_ASSERT_DISABLE(vs_size >= 0);  /* unsigned */
17919
17920         /* Use unsigned arithmetic to optimize comparison. */
17921         if (idx < 0) {
17922                 uidx = vs_size + (duk_uidx_t) idx;
17923         } else {
17924                 DUK_ASSERT(idx != DUK_INVALID_INDEX);
17925                 uidx = (duk_uidx_t) idx;
17926         }
17927
17928         /* DUK_INVALID_INDEX won't be accepted as a valid index. */
17929         DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
17930
17931         if (DUK_LIKELY(uidx < vs_size)) {
17932                 return thr->valstack_bottom + uidx;
17933         }
17934         DUK_ERROR_RANGE_INDEX(thr, idx);
17935         DUK_WO_NORETURN(return NULL;);
17936 }
17937
17938 /* Non-critical. */
17939 DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_hthread *thr, duk_idx_t idx) {
17940         DUK_ASSERT_API_ENTRY(thr);
17941         DUK_ASSERT(DUK_INVALID_INDEX < 0);
17942
17943         return (duk_normalize_index(thr, idx) >= 0);
17944 }
17945
17946 /* Non-critical. */
17947 DUK_EXTERNAL void duk_require_valid_index(duk_hthread *thr, duk_idx_t idx) {
17948         DUK_ASSERT_API_ENTRY(thr);
17949         DUK_ASSERT(DUK_INVALID_INDEX < 0);
17950
17951         if (DUK_UNLIKELY(duk_normalize_index(thr, idx) < 0)) {
17952                 DUK_ERROR_RANGE_INDEX(thr, idx);
17953                 DUK_WO_NORETURN(return;);
17954         }
17955 }
17956
17957 /*
17958  *  Value stack top handling
17959  */
17960
17961 DUK_EXTERNAL duk_idx_t duk_get_top(duk_hthread *thr) {
17962         DUK_ASSERT_API_ENTRY(thr);
17963
17964         return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
17965 }
17966
17967 /* Internal helper to get current top but to require a minimum top value
17968  * (TypeError if not met).
17969  */
17970 DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_hthread *thr, duk_idx_t min_top) {
17971         duk_idx_t ret;
17972
17973         DUK_ASSERT_API_ENTRY(thr);
17974
17975         ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
17976         if (DUK_UNLIKELY(ret < min_top)) {
17977                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
17978                 DUK_WO_NORETURN(return 0;);
17979         }
17980         return ret;
17981 }
17982
17983 /* Set stack top within currently allocated range, but don't reallocate.
17984  * This is performance critical especially for call handling, so whenever
17985  * changing, profile and look at generated code.
17986  */
17987 DUK_EXTERNAL void duk_set_top(duk_hthread *thr, duk_idx_t idx) {
17988         duk_uidx_t vs_size;
17989         duk_uidx_t vs_limit;
17990         duk_uidx_t uidx;
17991         duk_tval *tv;
17992
17993         DUK_ASSERT_API_ENTRY(thr);
17994         DUK_ASSERT(DUK_INVALID_INDEX < 0);
17995
17996         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
17997         DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
17998         vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
17999         vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom);
18000
18001         if (idx < 0) {
18002                 /* Negative indices are always within allocated stack but
18003                  * must not go below zero index.
18004                  */
18005                 uidx = vs_size + (duk_uidx_t) idx;
18006         } else {
18007                 /* Positive index can be higher than valstack top but must
18008                  * not go above allocated stack (equality is OK).
18009                  */
18010                 uidx = (duk_uidx_t) idx;
18011         }
18012
18013         /* DUK_INVALID_INDEX won't be accepted as a valid index. */
18014         DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
18015         DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit);
18016
18017 #if defined(DUK_USE_VALSTACK_UNSAFE)
18018         DUK_ASSERT(uidx <= vs_limit);
18019         DUK_UNREF(vs_limit);
18020 #else
18021         if (DUK_UNLIKELY(uidx > vs_limit)) {
18022                 DUK_ERROR_RANGE_INDEX(thr, idx);
18023                 DUK_WO_NORETURN(return;);
18024         }
18025 #endif
18026         DUK_ASSERT(uidx <= vs_limit);
18027
18028         /* Handle change in value stack top.  Respect value stack
18029          * initialization policy: 'undefined' above top.  Note that
18030          * DECREF may cause a side effect that reallocates valstack,
18031          * so must relookup after DECREF.
18032          */
18033
18034         if (uidx >= vs_size) {
18035                 /* Stack size increases or stays the same. */
18036 #if defined(DUK_USE_ASSERTIONS)
18037                 duk_uidx_t count;
18038
18039                 count = uidx - vs_size;
18040                 while (count != 0) {
18041                         count--;
18042                         tv = thr->valstack_top + count;
18043                         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
18044                 }
18045 #endif
18046                 thr->valstack_top = thr->valstack_bottom + uidx;
18047         } else {
18048                 /* Stack size decreases. */
18049 #if defined(DUK_USE_REFERENCE_COUNTING)
18050                 duk_uidx_t count;
18051                 duk_tval *tv_end;
18052
18053                 count = vs_size - uidx;
18054                 DUK_ASSERT(count > 0);
18055                 tv = thr->valstack_top;
18056                 tv_end = tv - count;
18057                 DUK_ASSERT(tv > tv_end);  /* Because count > 0. */
18058                 do {
18059                         tv--;
18060                         DUK_ASSERT(tv >= thr->valstack_bottom);
18061                         DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
18062                 } while (tv != tv_end);
18063                 thr->valstack_top = tv_end;
18064                 DUK_REFZERO_CHECK_FAST(thr);
18065 #else  /* DUK_USE_REFERENCE_COUNTING */
18066                 duk_uidx_t count;
18067                 duk_tval *tv_end;
18068
18069                 count = vs_size - uidx;
18070                 tv = thr->valstack_top;
18071                 tv_end = tv - count;
18072                 DUK_ASSERT(tv > tv_end);
18073                 do {
18074                         tv--;
18075                         DUK_TVAL_SET_UNDEFINED(tv);
18076                 } while (tv != tv_end);
18077                 thr->valstack_top = tv_end;
18078 #endif  /* DUK_USE_REFERENCE_COUNTING */
18079         }
18080 }
18081
18082 /* Internal variant with a non-negative index and no runtime size checks. */
18083 #if defined(DUK_USE_PREFER_SIZE)
18084 DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
18085         DUK_ASSERT_API_ENTRY(thr);
18086
18087         duk_set_top(thr, idx);
18088 }
18089 #else  /* DUK_USE_PREFER_SIZE */
18090 DUK_INTERNAL void duk_set_top_unsafe(duk_hthread *thr, duk_idx_t idx) {
18091         duk_uidx_t uidx;
18092         duk_uidx_t vs_size;
18093         duk_tval *tv;
18094
18095         DUK_ASSERT_API_ENTRY(thr);
18096         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18097         DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
18098         DUK_ASSERT(idx >= 0);
18099         DUK_ASSERT(idx <= (duk_idx_t) (thr->valstack_end - thr->valstack_bottom));
18100
18101         /* XXX: byte arithmetic */
18102         uidx = (duk_uidx_t) idx;
18103         vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
18104
18105         if (uidx >= vs_size) {
18106                 /* Stack size increases or stays the same. */
18107 #if defined(DUK_USE_ASSERTIONS)
18108                 duk_uidx_t count;
18109
18110                 count = uidx - vs_size;
18111                 while (count != 0) {
18112                         count--;
18113                         tv = thr->valstack_top + count;
18114                         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
18115                 }
18116 #endif
18117                 thr->valstack_top = thr->valstack_bottom + uidx;
18118         } else {
18119                 /* Stack size decreases. */
18120 #if defined(DUK_USE_REFERENCE_COUNTING)
18121                 duk_uidx_t count;
18122                 duk_tval *tv_end;
18123
18124                 count = vs_size - uidx;
18125                 DUK_ASSERT(count > 0);
18126                 tv = thr->valstack_top;
18127                 tv_end = tv - count;
18128                 DUK_ASSERT(tv > tv_end);  /* Because count > 0. */
18129                 do {
18130                         tv--;
18131                         DUK_ASSERT(tv >= thr->valstack_bottom);
18132                         DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
18133                 } while (tv != tv_end);
18134                 thr->valstack_top = tv_end;
18135                 DUK_REFZERO_CHECK_FAST(thr);
18136 #else  /* DUK_USE_REFERENCE_COUNTING */
18137                 duk_uidx_t count;
18138                 duk_tval *tv_end;
18139
18140                 count = vs_size - uidx;
18141                 tv = thr->valstack_top;
18142                 tv_end = tv - count;
18143                 DUK_ASSERT(tv > tv_end);
18144                 do {
18145                         tv--;
18146                         DUK_TVAL_SET_UNDEFINED(tv);
18147                 } while (tv != tv_end);
18148                 thr->valstack_top = tv_end;
18149 #endif  /* DUK_USE_REFERENCE_COUNTING */
18150         }
18151 }
18152 #endif  /* DUK_USE_PREFER_SIZE */
18153
18154 /* Internal helper: set top to 'top', and set [idx_wipe_start,top[ to
18155  * 'undefined' (doing nothing if idx_wipe_start == top).  Indices are
18156  * positive and within value stack reserve.  This is used by call handling.
18157  */
18158 DUK_INTERNAL void duk_set_top_and_wipe(duk_hthread *thr, duk_idx_t top, duk_idx_t idx_wipe_start) {
18159         DUK_ASSERT_API_ENTRY(thr);
18160         DUK_ASSERT(top >= 0);
18161         DUK_ASSERT(idx_wipe_start >= 0);
18162         DUK_ASSERT(idx_wipe_start <= top);
18163         DUK_ASSERT(thr->valstack_bottom + top <= thr->valstack_end);
18164         DUK_ASSERT(thr->valstack_bottom + idx_wipe_start <= thr->valstack_end);
18165
18166         duk_set_top_unsafe(thr, idx_wipe_start);
18167         duk_set_top_unsafe(thr, top);
18168 }
18169
18170 DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_hthread *thr) {
18171         duk_idx_t ret;
18172
18173         DUK_ASSERT_API_ENTRY(thr);
18174
18175         ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
18176         if (DUK_UNLIKELY(ret < 0)) {
18177                 /* Return invalid index; if caller uses this without checking
18178                  * in another API call, the index won't map to a valid stack
18179                  * entry.
18180                  */
18181                 return DUK_INVALID_INDEX;
18182         }
18183         return ret;
18184 }
18185
18186 /* Internal variant: call assumes there is at least one element on the value
18187  * stack frame; this is only asserted for.
18188  */
18189 DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_hthread *thr) {
18190         duk_idx_t ret;
18191
18192         DUK_ASSERT_API_ENTRY(thr);
18193
18194         ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
18195         return ret;
18196 }
18197
18198 DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_hthread *thr) {
18199         duk_idx_t ret;
18200
18201         DUK_ASSERT_API_ENTRY(thr);
18202
18203         ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
18204         if (DUK_UNLIKELY(ret < 0)) {
18205                 DUK_ERROR_RANGE_INDEX(thr, -1);
18206                 DUK_WO_NORETURN(return 0;);
18207         }
18208         return ret;
18209 }
18210
18211 /*
18212  *  Value stack resizing.
18213  *
18214  *  This resizing happens above the current "top": the value stack can be
18215  *  grown or shrunk, but the "top" is not affected.  The value stack cannot
18216  *  be resized to a size below the current reserve.
18217  *
18218  *  The low level reallocation primitive must carefully recompute all value
18219  *  stack pointers, and must also work if ALL pointers are NULL.  The resize
18220  *  is quite tricky because the valstack realloc may cause a mark-and-sweep,
18221  *  which may run finalizers.  Running finalizers may resize the valstack
18222  *  recursively (the same value stack we're working on).  So, after realloc
18223  *  returns, we know that the valstack bottom, top, and reserve should still
18224  *  be the same (there should not be live values above the "top"), but its
18225  *  underlying size, alloc_end, and base pointer may have changed.
18226  *
18227  *  'new_size' is known to be <= DUK_USE_VALSTACK_LIMIT, which ensures that
18228  *  size_t and pointer arithmetic won't wrap in duk__resize_valstack().
18229  */
18230
18231 /* Low level valstack resize primitive, used for both grow and shrink.  All
18232  * adjustments for slack etc have already been done.  Doesn't throw but does
18233  * have allocation side effects.
18234  */
18235 DUK_LOCAL DUK_COLD DUK_NOINLINE duk_bool_t duk__resize_valstack(duk_hthread *thr, duk_size_t new_size) {
18236         duk_tval *pre_valstack;
18237         duk_tval *pre_bottom;
18238         duk_tval *pre_top;
18239         duk_tval *pre_end;
18240         duk_tval *pre_alloc_end;
18241         duk_ptrdiff_t ptr_diff;
18242         duk_tval *new_valstack;
18243         duk_size_t new_alloc_size;
18244         duk_tval *tv_prev_alloc_end;
18245         duk_tval *p;
18246
18247         DUK_ASSERT_HTHREAD_VALID(thr);
18248         DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
18249         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18250         DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
18251         DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
18252         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size);  /* can't resize below 'top' */
18253         DUK_ASSERT(new_size <= DUK_USE_VALSTACK_LIMIT);  /* valstack limit caller has check, prevents wrapping */
18254         DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval));  /* specific assert for wrapping */
18255
18256         /* Pre-realloc pointer copies for asserts and debug logs. */
18257         pre_valstack = thr->valstack;
18258         pre_bottom = thr->valstack_bottom;
18259         pre_top = thr->valstack_top;
18260         pre_end = thr->valstack_end;
18261         pre_alloc_end = thr->valstack_alloc_end;
18262
18263         DUK_UNREF(pre_valstack);
18264         DUK_UNREF(pre_bottom);
18265         DUK_UNREF(pre_top);
18266         DUK_UNREF(pre_end);
18267         DUK_UNREF(pre_alloc_end);
18268
18269         /* If finalizer torture enabled, force base pointer change every time
18270          * when it would be allowed.
18271          */
18272 #if defined(DUK_USE_FINALIZER_TORTURE)
18273         if (thr->heap->pf_prevent_count == 0) {
18274                 duk_hthread_valstack_torture_realloc(thr);
18275         }
18276 #endif
18277
18278         /* Allocate a new valstack using DUK_REALLOC_DIRECT() to deal with
18279          * a side effect changing the base pointer.
18280          */
18281         new_alloc_size = sizeof(duk_tval) * new_size;
18282         new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
18283         if (DUK_UNLIKELY(new_valstack == NULL)) {
18284                 /* Because new_size != 0, if condition doesn't need to be
18285                  * (new_valstack != NULL || new_size == 0).
18286                  */
18287                 DUK_ASSERT(new_size != 0);
18288                 DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)",
18289                                  (unsigned long) new_size, (unsigned long) new_alloc_size));
18290                 return 0;
18291         }
18292
18293         /* Debug log any changes in pointer(s) by side effects.  These don't
18294          * necessarily imply any incorrect behavior, but should be rare in
18295          * practice.
18296          */
18297 #if defined(DUK_USE_DEBUG)
18298         if (thr->valstack != pre_valstack) {
18299                 DUK_D(DUK_DPRINT("valstack base pointer changed during valstack resize: %p -> %p",
18300                                  (void *) pre_valstack, (void *) thr->valstack));
18301         }
18302         if (thr->valstack_bottom != pre_bottom) {
18303                 DUK_D(DUK_DPRINT("valstack bottom pointer changed during valstack resize: %p -> %p",
18304                                  (void *) pre_bottom, (void *) thr->valstack_bottom));
18305         }
18306         if (thr->valstack_top != pre_top) {
18307                 DUK_D(DUK_DPRINT("valstack top pointer changed during valstack resize: %p -> %p",
18308                                  (void *) pre_top, (void *) thr->valstack_top));
18309         }
18310         if (thr->valstack_end != pre_end) {
18311                 DUK_D(DUK_DPRINT("valstack end pointer changed during valstack resize: %p -> %p",
18312                                  (void *) pre_end, (void *) thr->valstack_end));
18313         }
18314         if (thr->valstack_alloc_end != pre_alloc_end) {
18315                 DUK_D(DUK_DPRINT("valstack alloc_end pointer changed during valstack resize: %p -> %p",
18316                                  (void *) pre_alloc_end, (void *) thr->valstack_alloc_end));
18317         }
18318 #endif
18319
18320         /* Assertions: offsets for bottom, top, and end (reserve) must not
18321          * have changed even with side effects because they are always
18322          * restored in unwind.  For alloc_end there's no guarantee: it may
18323          * have grown or shrunk (but remain above 'end').
18324          */
18325         DUK_ASSERT(thr->valstack_bottom - thr->valstack == pre_bottom - pre_valstack);
18326         DUK_ASSERT(thr->valstack_top - thr->valstack == pre_top - pre_valstack);
18327         DUK_ASSERT(thr->valstack_end - thr->valstack == pre_end - pre_valstack);
18328         DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
18329
18330         /* Write new pointers.  Most pointers can be handled as a pointer
18331          * difference.
18332          */
18333         ptr_diff = (duk_ptrdiff_t) ((duk_uint8_t *) new_valstack - (duk_uint8_t *) thr->valstack);
18334         tv_prev_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_alloc_end + ptr_diff);
18335         thr->valstack = new_valstack;
18336         thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + ptr_diff);
18337         thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + ptr_diff);
18338         thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_end + ptr_diff);
18339         thr->valstack_alloc_end = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + new_alloc_size);
18340
18341         /* Assertions: pointer sanity after pointer updates. */
18342         DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
18343         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
18344         DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
18345         DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
18346
18347         DUK_D(DUK_DPRINT("resized valstack %lu -> %lu elements (%lu -> %lu bytes): "
18348                          "base=%p -> %p, bottom=%p -> %p (%ld), top=%p -> %p (%ld), "
18349                          "end=%p -> %p (%ld), alloc_end=%p -> %p (%ld);"
18350                          " tv_prev_alloc_end=%p (-> %ld inits; <0 means shrink)",
18351                          (unsigned long) (pre_alloc_end - pre_valstack),
18352                          (unsigned long) new_size,
18353                          (unsigned long) ((duk_uint8_t *) pre_alloc_end - (duk_uint8_t *) pre_valstack),
18354                          (unsigned long) new_alloc_size,
18355                          (void *) pre_valstack, (void *) thr->valstack,
18356                          (void *) pre_bottom, (void *) thr->valstack_bottom, (long) (thr->valstack_bottom - thr->valstack),
18357                          (void *) pre_top, (void *) thr->valstack_top, (long) (thr->valstack_top - thr->valstack),
18358                          (void *) pre_end, (void *) thr->valstack_end, (long) (thr->valstack_end - thr->valstack),
18359                          (void *) pre_alloc_end, (void *) thr->valstack_alloc_end, (long) (thr->valstack_alloc_end - thr->valstack),
18360                          (void *) tv_prev_alloc_end, (long) (thr->valstack_alloc_end - tv_prev_alloc_end)));
18361
18362         /* If allocation grew, init any new slots to 'undefined'. */
18363         p = tv_prev_alloc_end;
18364         while (p < thr->valstack_alloc_end) {
18365                 /* Never executed if new size is smaller. */
18366                 DUK_TVAL_SET_UNDEFINED(p);
18367                 p++;
18368         }
18369
18370         /* Assert for value stack initialization policy. */
18371 #if defined(DUK_USE_ASSERTIONS)
18372         p = thr->valstack_top;
18373         while (p < thr->valstack_alloc_end) {
18374                 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
18375                 p++;
18376         }
18377 #endif
18378
18379         return 1;
18380 }
18381
18382 DUK_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) {
18383         duk_size_t min_size;
18384         duk_size_t new_size;
18385
18386         DUK_ASSERT(min_bytes / sizeof(duk_tval) * sizeof(duk_tval) == min_bytes);
18387         min_size = min_bytes / sizeof(duk_tval);  /* from bytes to slots */
18388
18389 #if defined(DUK_USE_VALSTACK_GROW_SHIFT)
18390         /* New size is minimum size plus a proportional slack, e.g. shift of
18391          * 2 means a 25% slack.
18392          */
18393         new_size = min_size + (min_size >> DUK_USE_VALSTACK_GROW_SHIFT);
18394 #else
18395         /* New size is tight with no slack.  This is sometimes preferred in
18396          * low memory environments.
18397          */
18398         new_size = min_size;
18399 #endif
18400
18401         if (DUK_UNLIKELY(new_size > DUK_USE_VALSTACK_LIMIT || new_size < min_size /*wrap*/)) {
18402                 /* Note: may be triggered even if minimal new_size would not reach the limit,
18403                  * plan limit accordingly.
18404                  */
18405                 if (throw_on_error) {
18406                         DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
18407                         DUK_WO_NORETURN(return 0;);
18408                 }
18409                 return 0;
18410         }
18411
18412         if (duk__resize_valstack(thr, new_size) == 0) {
18413                 if (throw_on_error) {
18414                         DUK_ERROR_ALLOC_FAILED(thr);
18415                         DUK_WO_NORETURN(return 0;);
18416                 }
18417                 return 0;
18418         }
18419
18420         thr->valstack_end = thr->valstack + min_size;
18421         DUK_ASSERT(thr->valstack_alloc_end >= thr->valstack_end);
18422
18423         return 1;
18424 }
18425
18426 /* Hot, inlined value stack grow check.  Because value stack almost never
18427  * grows, the actual resize call is in a NOINLINE helper.
18428  */
18429 DUK_INTERNAL DUK_INLINE void duk_valstack_grow_check_throw(duk_hthread *thr, duk_size_t min_bytes) {
18430         duk_tval *tv;
18431
18432         tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
18433         if (DUK_LIKELY(thr->valstack_end >= tv)) {
18434                 return;
18435         }
18436         if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
18437                 /* Values in [valstack_top,valstack_alloc_end[ are initialized
18438                  * to 'undefined' so we can just move the end pointer.
18439                  */
18440                 thr->valstack_end = tv;
18441                 return;
18442         }
18443         (void) duk__valstack_grow(thr, min_bytes, 1 /*throw_on_error*/);
18444 }
18445
18446 /* Hot, inlined value stack grow check which doesn't throw. */
18447 DUK_INTERNAL DUK_INLINE duk_bool_t duk_valstack_grow_check_nothrow(duk_hthread *thr, duk_size_t min_bytes) {
18448         duk_tval *tv;
18449
18450         tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + min_bytes);
18451         if (DUK_LIKELY(thr->valstack_end >= tv)) {
18452                 return 1;
18453         }
18454         if (DUK_LIKELY(thr->valstack_alloc_end >= tv)) {
18455                 thr->valstack_end = tv;
18456                 return 1;
18457         }
18458         return duk__valstack_grow(thr, min_bytes, 0 /*throw_on_error*/);
18459 }
18460
18461 /* Value stack shrink check, called from mark-and-sweep. */
18462 DUK_INTERNAL void duk_valstack_shrink_check_nothrow(duk_hthread *thr, duk_bool_t snug) {
18463         duk_size_t alloc_bytes;
18464         duk_size_t reserve_bytes;
18465         duk_size_t shrink_bytes;
18466
18467         alloc_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
18468         reserve_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
18469         DUK_ASSERT(alloc_bytes >= reserve_bytes);
18470
18471         /* We're free to shrink the value stack allocation down to
18472          * reserve_bytes but not more.  If 'snug' (emergency GC)
18473          * shrink whatever we can.  Otherwise only shrink if the new
18474          * size would be considerably smaller.
18475          */
18476
18477 #if defined(DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT)
18478         if (snug) {
18479                 shrink_bytes = reserve_bytes;
18480         } else {
18481                 duk_size_t proportion, slack;
18482
18483                 /* Require that value stack shrinks by at least X% of its
18484                  * current size.  For example, shift of 2 means at least
18485                  * 25%.  The proportion is computed as bytes and may not
18486                  * be a multiple of sizeof(duk_tval); that's OK here.
18487                  */
18488                 proportion = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT;
18489                 if (alloc_bytes - reserve_bytes < proportion) {
18490                         /* Too little would be freed, do nothing. */
18491                         return;
18492                 }
18493
18494                 /* Keep a slack after shrinking.  The slack is again a
18495                  * proportion of the current size (the proportion should
18496                  * of course be smaller than the check proportion above).
18497                  */
18498 #if defined(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT)
18499                 DUK_ASSERT(DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT > DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT);
18500                 slack = alloc_bytes >> DUK_USE_VALSTACK_SHRINK_SLACK_SHIFT;
18501 #else
18502                 slack = 0;
18503 #endif
18504                 shrink_bytes = reserve_bytes +
18505                                slack / sizeof(duk_tval) * sizeof(duk_tval);  /* multiple of duk_tval */
18506         }
18507 #else  /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
18508         /* Always snug, useful in some low memory environments. */
18509         DUK_UNREF(snug);
18510         shrink_bytes = reserve_bytes;
18511 #endif  /* DUK_USE_VALSTACK_SHRINK_CHECK_SHIFT */
18512
18513         DUK_D(DUK_DPRINT("valstack shrink check: alloc_bytes=%ld, reserve_bytes=%ld, shrink_bytes=%ld (unvalidated)",
18514                          (long) alloc_bytes, (long) reserve_bytes, (long) shrink_bytes));
18515         DUK_ASSERT(shrink_bytes >= reserve_bytes);
18516         if (shrink_bytes >= alloc_bytes) {
18517                 /* Skip if shrink target is same as current one (or higher,
18518                  * though that shouldn't happen in practice).
18519                  */
18520                 return;
18521         }
18522         DUK_ASSERT(shrink_bytes / sizeof(duk_tval) * sizeof(duk_tval) == shrink_bytes);
18523
18524         DUK_D(DUK_DPRINT("valstack shrink check: decided to shrink, snug: %ld", (long) snug));
18525
18526         duk__resize_valstack(thr, shrink_bytes / sizeof(duk_tval));
18527 }
18528
18529 DUK_EXTERNAL duk_bool_t duk_check_stack(duk_hthread *thr, duk_idx_t extra) {
18530         duk_size_t min_new_bytes;
18531
18532         DUK_ASSERT_API_ENTRY(thr);
18533         DUK_ASSERT(thr != NULL);
18534
18535         if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
18536                 if (extra < 0) {
18537                         /* Clamping to zero makes the API more robust to calling code
18538                          * calculation errors.
18539                          */
18540                         extra = 0;
18541                 } else {
18542                         /* Cause grow check to fail without wrapping arithmetic. */
18543                         extra = DUK_USE_VALSTACK_LIMIT;
18544                 }
18545         }
18546
18547         min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
18548                         sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
18549         return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
18550 }
18551
18552 DUK_EXTERNAL void duk_require_stack(duk_hthread *thr, duk_idx_t extra) {
18553         duk_size_t min_new_bytes;
18554
18555         DUK_ASSERT_API_ENTRY(thr);
18556         DUK_ASSERT(thr != NULL);
18557
18558         if (DUK_UNLIKELY(extra < 0 || extra > DUK_USE_VALSTACK_LIMIT)) {
18559                 if (extra < 0) {
18560                         /* Clamping to zero makes the API more robust to calling code
18561                          * calculation errors.
18562                          */
18563                         extra = 0;
18564                 } else {
18565                         /* Cause grow check to fail without wrapping arithmetic. */
18566                         extra = DUK_USE_VALSTACK_LIMIT;
18567                 }
18568         }
18569
18570         min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack) +
18571                         sizeof(duk_tval) * ((duk_size_t) extra + DUK_VALSTACK_INTERNAL_EXTRA);
18572         duk_valstack_grow_check_throw(thr, min_new_bytes);
18573 }
18574
18575 DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_hthread *thr, duk_idx_t top) {
18576         duk_size_t min_new_bytes;
18577
18578         DUK_ASSERT_API_ENTRY(thr);
18579
18580         if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
18581                 if (top < 0) {
18582                         /* Clamping to zero makes the API more robust to calling code
18583                          * calculation errors.
18584                          */
18585                         top = 0;
18586                 } else {
18587                         /* Cause grow check to fail without wrapping arithmetic. */
18588                         top = DUK_USE_VALSTACK_LIMIT;
18589                 }
18590         }
18591
18592         DUK_ASSERT(top >= 0);
18593         min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
18594                         sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
18595         return duk_valstack_grow_check_nothrow(thr, min_new_bytes);
18596 }
18597
18598 DUK_EXTERNAL void duk_require_stack_top(duk_hthread *thr, duk_idx_t top) {
18599         duk_size_t min_new_bytes;
18600
18601         DUK_ASSERT_API_ENTRY(thr);
18602
18603         if (DUK_UNLIKELY(top < 0 || top > DUK_USE_VALSTACK_LIMIT)) {
18604                 if (top < 0) {
18605                         /* Clamping to zero makes the API more robust to calling code
18606                          * calculation errors.
18607                          */
18608                         top = 0;
18609                 } else {
18610                         /* Cause grow check to fail without wrapping arithmetic. */
18611                         top = DUK_USE_VALSTACK_LIMIT;
18612                 }
18613         }
18614
18615         DUK_ASSERT(top >= 0);
18616         min_new_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) +
18617                         sizeof(duk_tval) * ((duk_size_t) top + DUK_VALSTACK_INTERNAL_EXTRA);
18618         duk_valstack_grow_check_throw(thr, min_new_bytes);
18619 }
18620
18621 /*
18622  *  Basic stack manipulation: swap, dup, insert, replace, etc
18623  */
18624
18625 DUK_EXTERNAL void duk_swap(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
18626         duk_tval *tv1;
18627         duk_tval *tv2;
18628         duk_tval tv_tmp;
18629
18630         DUK_ASSERT_API_ENTRY(thr);
18631
18632         tv1 = duk_require_tval(thr, idx1);
18633         DUK_ASSERT(tv1 != NULL);
18634         tv2 = duk_require_tval(thr, idx2);
18635         DUK_ASSERT(tv2 != NULL);
18636
18637         /* If tv1==tv2 this is a NOP, no check is needed */
18638         DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
18639         DUK_TVAL_SET_TVAL(tv1, tv2);
18640         DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
18641 }
18642
18643 DUK_EXTERNAL void duk_swap_top(duk_hthread *thr, duk_idx_t idx) {
18644         DUK_ASSERT_API_ENTRY(thr);
18645
18646         duk_swap(thr, idx, -1);
18647 }
18648
18649 DUK_EXTERNAL void duk_dup(duk_hthread *thr, duk_idx_t from_idx) {
18650         duk_tval *tv_from;
18651         duk_tval *tv_to;
18652
18653         DUK_ASSERT_API_ENTRY(thr);
18654         DUK__CHECK_SPACE();
18655
18656         tv_from = duk_require_tval(thr, from_idx);
18657         tv_to = thr->valstack_top++;
18658         DUK_ASSERT(tv_from != NULL);
18659         DUK_ASSERT(tv_to != NULL);
18660         DUK_TVAL_SET_TVAL(tv_to, tv_from);
18661         DUK_TVAL_INCREF(thr, tv_to);  /* no side effects */
18662 }
18663
18664 DUK_EXTERNAL void duk_dup_top(duk_hthread *thr) {
18665 #if defined(DUK_USE_PREFER_SIZE)
18666         duk_dup(thr, -1);
18667 #else
18668         duk_tval *tv_from;
18669         duk_tval *tv_to;
18670
18671         DUK_ASSERT_API_ENTRY(thr);
18672         DUK__CHECK_SPACE();
18673
18674         if (DUK_UNLIKELY(thr->valstack_top - thr->valstack_bottom <= 0)) {
18675                 DUK_ERROR_RANGE_INDEX(thr, -1);
18676                 DUK_WO_NORETURN(return;);
18677         }
18678         tv_from = thr->valstack_top - 1;
18679         tv_to = thr->valstack_top++;
18680         DUK_ASSERT(tv_from != NULL);
18681         DUK_ASSERT(tv_to != NULL);
18682         DUK_TVAL_SET_TVAL(tv_to, tv_from);
18683         DUK_TVAL_INCREF(thr, tv_to);  /* no side effects */
18684 #endif
18685 }
18686
18687 DUK_INTERNAL void duk_dup_0(duk_hthread *thr) {
18688         DUK_ASSERT_API_ENTRY(thr);
18689         duk_dup(thr, 0);
18690 }
18691 DUK_INTERNAL void duk_dup_1(duk_hthread *thr) {
18692         DUK_ASSERT_API_ENTRY(thr);
18693         duk_dup(thr, 1);
18694 }
18695 DUK_INTERNAL void duk_dup_2(duk_hthread *thr) {
18696         DUK_ASSERT_API_ENTRY(thr);
18697         duk_dup(thr, 2);
18698 }
18699 DUK_INTERNAL void duk_dup_m2(duk_hthread *thr) {
18700         DUK_ASSERT_API_ENTRY(thr);
18701         duk_dup(thr, -2);
18702 }
18703 DUK_INTERNAL void duk_dup_m3(duk_hthread *thr) {
18704         DUK_ASSERT_API_ENTRY(thr);
18705         duk_dup(thr, -3);
18706 }
18707 DUK_INTERNAL void duk_dup_m4(duk_hthread *thr) {
18708         DUK_ASSERT_API_ENTRY(thr);
18709         duk_dup(thr, -4);
18710 }
18711
18712 DUK_EXTERNAL void duk_insert(duk_hthread *thr, duk_idx_t to_idx) {
18713         duk_tval *p;
18714         duk_tval *q;
18715         duk_tval tv_tmp;
18716         duk_size_t nbytes;
18717
18718         DUK_ASSERT_API_ENTRY(thr);
18719
18720         p = duk_require_tval(thr, to_idx);
18721         DUK_ASSERT(p != NULL);
18722         q = duk_require_tval(thr, -1);
18723         DUK_ASSERT(q != NULL);
18724
18725         DUK_ASSERT(q >= p);
18726
18727         /*              nbytes
18728          *           <--------->
18729          *    [ ... | p | x | x | q ]
18730          * => [ ... | q | p | x | x ]
18731          */
18732
18733         nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p));  /* Note: 'q' is top-1 */
18734
18735         DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu",
18736                              (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes));
18737
18738         /* No net refcount changes.  No need to special case nbytes == 0
18739          * (p == q).
18740          */
18741         DUK_TVAL_SET_TVAL(&tv_tmp, q);
18742         duk_memmove((void *) (p + 1), (const void *) p, (size_t) nbytes);
18743         DUK_TVAL_SET_TVAL(p, &tv_tmp);
18744 }
18745
18746 DUK_INTERNAL void duk_insert_undefined(duk_hthread *thr, duk_idx_t idx) {
18747         DUK_ASSERT_API_ENTRY(thr);
18748         DUK_ASSERT(idx >= 0);  /* Doesn't support negative indices. */
18749
18750         duk_push_undefined(thr);
18751         duk_insert(thr, idx);
18752 }
18753
18754 DUK_INTERNAL void duk_insert_undefined_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
18755         duk_tval *tv, *tv_end;
18756
18757         DUK_ASSERT_API_ENTRY(thr);
18758         DUK_ASSERT(idx >= 0);  /* Doesn't support negative indices or count. */
18759         DUK_ASSERT(count >= 0);
18760
18761         tv = duk_reserve_gap(thr, idx, count);
18762         tv_end = tv + count;
18763         while (tv != tv_end) {
18764                 DUK_TVAL_SET_UNDEFINED(tv);
18765                 tv++;
18766         }
18767 }
18768
18769 DUK_EXTERNAL void duk_replace(duk_hthread *thr, duk_idx_t to_idx) {
18770         duk_tval *tv1;
18771         duk_tval *tv2;
18772         duk_tval tv_tmp;
18773
18774         DUK_ASSERT_API_ENTRY(thr);
18775
18776         tv1 = duk_require_tval(thr, -1);
18777         DUK_ASSERT(tv1 != NULL);
18778         tv2 = duk_require_tval(thr, to_idx);
18779         DUK_ASSERT(tv2 != NULL);
18780
18781         /* For tv1 == tv2, both pointing to stack top, the end result
18782          * is same as duk_pop(thr).
18783          */
18784         DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
18785         DUK_TVAL_SET_TVAL(tv2, tv1);
18786         DUK_TVAL_SET_UNDEFINED(tv1);
18787         thr->valstack_top--;
18788         DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
18789 }
18790
18791 DUK_EXTERNAL void duk_copy(duk_hthread *thr, duk_idx_t from_idx, duk_idx_t to_idx) {
18792         duk_tval *tv1;
18793         duk_tval *tv2;
18794
18795         DUK_ASSERT_API_ENTRY(thr);
18796
18797         tv1 = duk_require_tval(thr, from_idx);
18798         DUK_ASSERT(tv1 != NULL);
18799         tv2 = duk_require_tval(thr, to_idx);
18800         DUK_ASSERT(tv2 != NULL);
18801
18802         /* For tv1 == tv2, this is a no-op (no explicit check needed). */
18803         DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1);  /* side effects */
18804 }
18805
18806 DUK_EXTERNAL void duk_remove(duk_hthread *thr, duk_idx_t idx) {
18807         duk_tval *p;
18808         duk_tval *q;
18809 #if defined(DUK_USE_REFERENCE_COUNTING)
18810         duk_tval tv_tmp;
18811 #endif
18812         duk_size_t nbytes;
18813
18814         DUK_ASSERT_API_ENTRY(thr);
18815
18816         p = duk_require_tval(thr, idx);
18817         DUK_ASSERT(p != NULL);
18818         q = duk_require_tval(thr, -1);
18819         DUK_ASSERT(q != NULL);
18820
18821         DUK_ASSERT(q >= p);
18822
18823         /*              nbytes            zero size case
18824          *           <--------->
18825          *    [ ... | p | x | x | q ]     [ ... | p==q ]
18826          * => [ ... | x | x | q ]         [ ... ]
18827          */
18828
18829 #if defined(DUK_USE_REFERENCE_COUNTING)
18830         /* use a temp: decref only when valstack reachable values are correct */
18831         DUK_TVAL_SET_TVAL(&tv_tmp, p);
18832 #endif
18833
18834         nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p));  /* Note: 'q' is top-1 */
18835         duk_memmove((void *) p, (const void *) (p + 1), (size_t) nbytes);
18836
18837         DUK_TVAL_SET_UNDEFINED(q);
18838         thr->valstack_top--;
18839
18840 #if defined(DUK_USE_REFERENCE_COUNTING)
18841         DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
18842 #endif
18843 }
18844
18845 DUK_INTERNAL void duk_remove_unsafe(duk_hthread *thr, duk_idx_t idx) {
18846         DUK_ASSERT_API_ENTRY(thr);
18847
18848         duk_remove(thr, idx);  /* XXX: no optimization for now */
18849 }
18850
18851 DUK_INTERNAL void duk_remove_m2(duk_hthread *thr) {
18852         DUK_ASSERT_API_ENTRY(thr);
18853
18854         duk_remove(thr, -2);
18855 }
18856
18857 DUK_INTERNAL void duk_remove_n(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
18858 #if defined(DUK_USE_PREFER_SIZE)
18859         /* XXX: maybe too slow even when preferring size? */
18860         DUK_ASSERT_API_ENTRY(thr);
18861         DUK_ASSERT(count >= 0);
18862         DUK_ASSERT(idx >= 0);
18863
18864         while (count-- > 0) {
18865                 duk_remove(thr, idx);
18866         }
18867 #else  /* DUK_USE_PREFER_SIZE */
18868         duk_tval *tv_src;
18869         duk_tval *tv_dst;
18870         duk_tval *tv_newtop;
18871         duk_tval *tv;
18872         duk_size_t bytes;
18873
18874         DUK_ASSERT_API_ENTRY(thr);
18875         DUK_ASSERT(count >= 0);
18876         DUK_ASSERT(idx >= 0);
18877
18878         tv_dst = thr->valstack_bottom + idx;
18879         DUK_ASSERT(tv_dst <= thr->valstack_top);
18880         tv_src = tv_dst + count;
18881         DUK_ASSERT(tv_src <= thr->valstack_top);
18882         bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
18883
18884         for (tv = tv_dst; tv < tv_src; tv++) {
18885                 DUK_TVAL_DECREF_NORZ(thr, tv);
18886         }
18887
18888         duk_memmove((void *) tv_dst, (const void *) tv_src, bytes);
18889
18890         tv_newtop = thr->valstack_top - count;
18891         for (tv = tv_newtop; tv < thr->valstack_top; tv++) {
18892                 DUK_TVAL_SET_UNDEFINED(tv);
18893         }
18894         thr->valstack_top = tv_newtop;
18895
18896         /* When not preferring size, only NORZ macros are used; caller
18897          * is expected to DUK_REFZERO_CHECK().
18898          */
18899 #endif  /* DUK_USE_PREFER_SIZE */
18900 }
18901
18902 DUK_INTERNAL void duk_remove_n_unsafe(duk_hthread *thr, duk_idx_t idx, duk_idx_t count) {
18903         DUK_ASSERT_API_ENTRY(thr);
18904
18905         duk_remove_n(thr, idx, count);  /* XXX: no optimization for now */
18906 }
18907
18908 /*
18909  *  Stack slice primitives
18910  */
18911
18912 DUK_EXTERNAL void duk_xcopymove_raw(duk_hthread *to_thr, duk_hthread *from_thr, duk_idx_t count, duk_bool_t is_copy) {
18913         void *src;
18914         duk_size_t nbytes;
18915         duk_tval *p;
18916         duk_tval *q;
18917
18918         /* XXX: several pointer comparison issues here */
18919
18920         DUK_ASSERT_API_ENTRY(to_thr);
18921         DUK_ASSERT_CTX_VALID(to_thr);
18922         DUK_ASSERT_CTX_VALID(from_thr);
18923         DUK_ASSERT(to_thr->heap == from_thr->heap);
18924
18925         if (DUK_UNLIKELY(to_thr == from_thr)) {
18926                 DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT);
18927                 DUK_WO_NORETURN(return;);
18928         }
18929         if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) DUK_USE_VALSTACK_LIMIT)) {
18930                 /* Maximum value check ensures 'nbytes' won't wrap below.
18931                  * Also handles negative count.
18932                  */
18933                 DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
18934                 DUK_WO_NORETURN(return;);
18935         }
18936         DUK_ASSERT(count >= 0);
18937
18938         nbytes = sizeof(duk_tval) * (duk_size_t) count;
18939         if (DUK_UNLIKELY(nbytes == 0)) {
18940                 return;
18941         }
18942         DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
18943         if (DUK_UNLIKELY((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes)) {
18944                 DUK_ERROR_RANGE_PUSH_BEYOND(to_thr);
18945                 DUK_WO_NORETURN(return;);
18946         }
18947         src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
18948         if (DUK_UNLIKELY(src < (void *) from_thr->valstack_bottom)) {
18949                 DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
18950                 DUK_WO_NORETURN(return;);
18951         }
18952
18953         /* Copy values (no overlap even if to_thr == from_thr; that's not
18954          * allowed now anyway).
18955          */
18956         DUK_ASSERT(nbytes > 0);
18957         duk_memcpy((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
18958
18959         p = to_thr->valstack_top;
18960         to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes);
18961
18962         if (is_copy) {
18963                 /* Incref copies, keep originals. */
18964                 q = to_thr->valstack_top;
18965                 while (p < q) {
18966                         DUK_TVAL_INCREF(to_thr, p);  /* no side effects */
18967                         p++;
18968                 }
18969         } else {
18970                 /* No net refcount change. */
18971                 p = from_thr->valstack_top;
18972                 q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes);
18973                 from_thr->valstack_top = q;
18974
18975                 while (p > q) {
18976                         p--;
18977                         DUK_TVAL_SET_UNDEFINED(p);
18978                         /* XXX: fast primitive to set a bunch of values to UNDEFINED */
18979                 }
18980         }
18981 }
18982
18983 /* Internal helper: reserve a gap of 'count' elements at 'idx_base' and return a
18984  * pointer to the gap.  Values in the gap are garbage and MUST be initialized by
18985  * the caller before any side effects may occur.  The caller must ensure there's
18986  * enough stack reserve for 'count' values.
18987  */
18988 DUK_INTERNAL duk_tval *duk_reserve_gap(duk_hthread *thr, duk_idx_t idx_base, duk_idx_t count) {
18989         duk_tval *tv_src;
18990         duk_tval *tv_dst;
18991         duk_size_t gap_bytes;
18992         duk_size_t copy_bytes;
18993
18994         /* Caller is responsible for ensuring there's enough preallocated
18995          * value stack.
18996          */
18997         DUK_ASSERT_API_ENTRY(thr);
18998         DUK_ASSERT(count >= 0);
18999         DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack_top) >= (duk_size_t) count);
19000
19001         tv_src = thr->valstack_bottom + idx_base;
19002         gap_bytes = (duk_size_t) count * sizeof(duk_tval);
19003         tv_dst = (duk_tval *) (void *) ((duk_uint8_t *) tv_src + gap_bytes);
19004         copy_bytes = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) tv_src);
19005         thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_top + gap_bytes);
19006         duk_memmove((void *) tv_dst, (const void *) tv_src, copy_bytes);
19007
19008         /* Values in the gap are left as garbage: caller must fill them in
19009          * and INCREF them before any side effects.
19010          */
19011         return tv_src;
19012 }
19013
19014 /*
19015  *  Get/opt/require
19016  */
19017
19018 DUK_EXTERNAL void duk_require_undefined(duk_hthread *thr, duk_idx_t idx) {
19019         duk_tval *tv;
19020
19021         DUK_ASSERT_API_ENTRY(thr);
19022
19023         tv = duk_get_tval_or_unused(thr, idx);
19024         DUK_ASSERT(tv != NULL);
19025         if (DUK_UNLIKELY(!DUK_TVAL_IS_UNDEFINED(tv))) {
19026                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED);
19027                 DUK_WO_NORETURN(return;);
19028         }
19029 }
19030
19031 DUK_EXTERNAL void duk_require_null(duk_hthread *thr, duk_idx_t idx) {
19032         duk_tval *tv;
19033
19034         DUK_ASSERT_API_ENTRY(thr);
19035
19036         tv = duk_get_tval_or_unused(thr, idx);
19037         DUK_ASSERT(tv != NULL);
19038         if (DUK_UNLIKELY(!DUK_TVAL_IS_NULL(tv))) {
19039                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL);
19040                 DUK_WO_NORETURN(return;);
19041         }
19042 }
19043
19044 DUK_LOCAL DUK_ALWAYS_INLINE duk_bool_t duk__get_boolean_raw(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
19045         duk_bool_t ret;
19046         duk_tval *tv;
19047
19048         DUK_ASSERT_CTX_VALID(thr);
19049
19050         tv = duk_get_tval_or_unused(thr, idx);
19051         DUK_ASSERT(tv != NULL);
19052         if (DUK_TVAL_IS_BOOLEAN(tv)) {
19053                 ret = DUK_TVAL_GET_BOOLEAN(tv);
19054                 DUK_ASSERT(ret == 0 || ret == 1);
19055         } else {
19056                 ret = def_value;
19057                 /* Not guaranteed to be 0 or 1. */
19058         }
19059
19060         return ret;
19061 }
19062
19063 DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_hthread *thr, duk_idx_t idx) {
19064         DUK_ASSERT_API_ENTRY(thr);
19065
19066         return duk__get_boolean_raw(thr, idx, 0);  /* default: false */
19067 }
19068
19069 DUK_EXTERNAL duk_bool_t duk_get_boolean_default(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
19070         DUK_ASSERT_API_ENTRY(thr);
19071
19072         return duk__get_boolean_raw(thr, idx, def_value);
19073 }
19074
19075 DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_hthread *thr, duk_idx_t idx) {
19076         duk_tval *tv;
19077         duk_bool_t ret;
19078
19079         DUK_ASSERT_API_ENTRY(thr);
19080
19081         tv = duk_get_tval_or_unused(thr, idx);
19082         DUK_ASSERT(tv != NULL);
19083         if (DUK_LIKELY(DUK_TVAL_IS_BOOLEAN(tv))) {
19084                 ret = DUK_TVAL_GET_BOOLEAN(tv);
19085                 DUK_ASSERT(ret == 0 || ret == 1);
19086                 return ret;
19087         } else {
19088                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN);
19089                 DUK_WO_NORETURN(return 0;);
19090         }
19091 }
19092
19093 DUK_EXTERNAL duk_bool_t duk_opt_boolean(duk_hthread *thr, duk_idx_t idx, duk_bool_t def_value) {
19094         DUK_ASSERT_API_ENTRY(thr);
19095
19096         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19097                 return def_value;
19098         }
19099         return duk_require_boolean(thr, idx);
19100 }
19101
19102 DUK_LOCAL DUK_ALWAYS_INLINE duk_double_t duk__get_number_raw(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
19103         duk_double_union ret;
19104         duk_tval *tv;
19105
19106         DUK_ASSERT_CTX_VALID(thr);
19107
19108         tv = duk_get_tval_or_unused(thr, idx);
19109         DUK_ASSERT(tv != NULL);
19110 #if defined(DUK_USE_FASTINT)
19111         if (DUK_TVAL_IS_FASTINT(tv)) {
19112                 ret.d = (duk_double_t) DUK_TVAL_GET_FASTINT(tv);  /* XXX: cast trick */
19113         }
19114         else
19115 #endif
19116         if (DUK_TVAL_IS_DOUBLE(tv)) {
19117                 /* When using packed duk_tval, number must be in NaN-normalized form
19118                  * for it to be a duk_tval, so no need to normalize.  NOP for unpacked
19119                  * duk_tval.
19120                  */
19121                 ret.d = DUK_TVAL_GET_DOUBLE(tv);
19122                 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
19123         } else {
19124                 ret.d = def_value;
19125                 /* Default value (including NaN) may not be normalized. */
19126         }
19127
19128         return ret.d;
19129 }
19130
19131 DUK_EXTERNAL duk_double_t duk_get_number(duk_hthread *thr, duk_idx_t idx) {
19132         DUK_ASSERT_API_ENTRY(thr);
19133         return duk__get_number_raw(thr, idx, DUK_DOUBLE_NAN);  /* default: NaN */
19134 }
19135
19136 DUK_EXTERNAL duk_double_t duk_get_number_default(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
19137         DUK_ASSERT_API_ENTRY(thr);
19138         return duk__get_number_raw(thr, idx, def_value);
19139 }
19140
19141 DUK_EXTERNAL duk_double_t duk_require_number(duk_hthread *thr, duk_idx_t idx) {
19142         duk_tval *tv;
19143         duk_double_union ret;
19144
19145         DUK_ASSERT_API_ENTRY(thr);
19146
19147         tv = duk_get_tval_or_unused(thr, idx);
19148         DUK_ASSERT(tv != NULL);
19149         if (DUK_UNLIKELY(!DUK_TVAL_IS_NUMBER(tv))) {
19150                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
19151                 DUK_WO_NORETURN(return 0.0;);
19152         }
19153
19154         ret.d = DUK_TVAL_GET_NUMBER(tv);
19155
19156         /* When using packed duk_tval, number must be in NaN-normalized form
19157          * for it to be a duk_tval, so no need to normalize.  NOP for unpacked
19158          * duk_tval.
19159          */
19160         DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
19161         return ret.d;
19162 }
19163
19164 DUK_EXTERNAL duk_double_t duk_opt_number(duk_hthread *thr, duk_idx_t idx, duk_double_t def_value) {
19165         DUK_ASSERT_API_ENTRY(thr);
19166
19167         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19168                 /* User provided default is not NaN normalized. */
19169                 return def_value;
19170         }
19171         return duk_require_number(thr, idx);
19172 }
19173
19174 DUK_EXTERNAL duk_int_t duk_get_int(duk_hthread *thr, duk_idx_t idx) {
19175         DUK_ASSERT_API_ENTRY(thr);
19176
19177         return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
19178 }
19179
19180 DUK_EXTERNAL duk_uint_t duk_get_uint(duk_hthread *thr, duk_idx_t idx) {
19181         DUK_ASSERT_API_ENTRY(thr);
19182
19183         return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
19184 }
19185
19186 DUK_EXTERNAL duk_int_t duk_get_int_default(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
19187         DUK_ASSERT_API_ENTRY(thr);
19188
19189         return (duk_int_t) duk__api_coerce_d2i(thr, idx, def_value, 0 /*require*/);
19190 }
19191
19192 DUK_EXTERNAL duk_uint_t duk_get_uint_default(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
19193         DUK_ASSERT_API_ENTRY(thr);
19194
19195         return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, def_value, 0 /*require*/);
19196 }
19197
19198 DUK_EXTERNAL duk_int_t duk_require_int(duk_hthread *thr, duk_idx_t idx) {
19199         DUK_ASSERT_API_ENTRY(thr);
19200
19201         return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 1 /*require*/);
19202 }
19203
19204 DUK_EXTERNAL duk_uint_t duk_require_uint(duk_hthread *thr, duk_idx_t idx) {
19205         DUK_ASSERT_API_ENTRY(thr);
19206
19207         return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 1 /*require*/);
19208 }
19209
19210 DUK_EXTERNAL duk_int_t duk_opt_int(duk_hthread *thr, duk_idx_t idx, duk_int_t def_value) {
19211         DUK_ASSERT_API_ENTRY(thr);
19212
19213         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19214                 return def_value;
19215         }
19216         return duk_require_int(thr, idx);
19217 }
19218
19219 DUK_EXTERNAL duk_uint_t duk_opt_uint(duk_hthread *thr, duk_idx_t idx, duk_uint_t def_value) {
19220         DUK_ASSERT_API_ENTRY(thr);
19221
19222         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19223                 return def_value;
19224         }
19225         return duk_require_uint(thr, idx);
19226 }
19227
19228 DUK_EXTERNAL const char *duk_get_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
19229         duk_hstring *h;
19230         const char *ret;
19231         duk_size_t len;
19232
19233         DUK_ASSERT_API_ENTRY(thr);
19234
19235         h = duk_get_hstring(thr, idx);
19236         if (h != NULL) {
19237                 len = DUK_HSTRING_GET_BYTELEN(h);
19238                 ret = (const char *) DUK_HSTRING_GET_DATA(h);
19239         } else {
19240                 len = 0;
19241                 ret = NULL;
19242         }
19243
19244         if (out_len != NULL) {
19245                 *out_len = len;
19246         }
19247         return ret;
19248 }
19249
19250 DUK_EXTERNAL const char *duk_require_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
19251         duk_hstring *h;
19252
19253         DUK_ASSERT_API_ENTRY(thr);
19254
19255         h = duk_require_hstring(thr, idx);
19256         DUK_ASSERT(h != NULL);
19257         if (out_len) {
19258                 *out_len = DUK_HSTRING_GET_BYTELEN(h);
19259         }
19260         return (const char *) DUK_HSTRING_GET_DATA(h);
19261 }
19262
19263 DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
19264         duk_hstring *h;
19265
19266         DUK_ASSERT_API_ENTRY(thr);
19267
19268         h = duk_require_hstring_notsymbol(thr, idx);
19269         DUK_ASSERT(h != NULL);
19270         if (out_len) {
19271                 *out_len = DUK_HSTRING_GET_BYTELEN(h);
19272         }
19273         return (const char *) DUK_HSTRING_GET_DATA(h);
19274 }
19275
19276 DUK_EXTERNAL const char *duk_get_string(duk_hthread *thr, duk_idx_t idx) {
19277         duk_hstring *h;
19278
19279         DUK_ASSERT_API_ENTRY(thr);
19280
19281         h = duk_get_hstring(thr, idx);
19282         if (h != NULL) {
19283                 return (const char *) DUK_HSTRING_GET_DATA(h);
19284         } else {
19285                 return NULL;
19286         }
19287 }
19288
19289 DUK_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) {
19290         DUK_ASSERT_API_ENTRY(thr);
19291
19292         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19293                 if (out_len != NULL) {
19294                         *out_len = def_len;
19295                 }
19296                 return def_ptr;
19297         }
19298         return duk_require_lstring(thr, idx, out_len);
19299 }
19300
19301 DUK_EXTERNAL const char *duk_opt_string(duk_hthread *thr, duk_idx_t idx, const char *def_ptr) {
19302         DUK_ASSERT_API_ENTRY(thr);
19303
19304         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19305                 return def_ptr;
19306         }
19307         return duk_require_string(thr, idx);
19308 }
19309
19310 DUK_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) {
19311         duk_hstring *h;
19312         const char *ret;
19313         duk_size_t len;
19314
19315         DUK_ASSERT_API_ENTRY(thr);
19316
19317         h = duk_get_hstring(thr, idx);
19318         if (h != NULL) {
19319                 len = DUK_HSTRING_GET_BYTELEN(h);
19320                 ret = (const char *) DUK_HSTRING_GET_DATA(h);
19321         } else {
19322                 len = def_len;
19323                 ret = def_ptr;
19324         }
19325
19326         if (out_len != NULL) {
19327                 *out_len = len;
19328         }
19329         return ret;
19330 }
19331
19332 DUK_EXTERNAL const char *duk_get_string_default(duk_hthread *thr, duk_idx_t idx, const char *def_value) {
19333         duk_hstring *h;
19334
19335         DUK_ASSERT_API_ENTRY(thr);
19336
19337         h = duk_get_hstring(thr, idx);
19338         if (h != NULL) {
19339                 return (const char *) DUK_HSTRING_GET_DATA(h);
19340         } else {
19341                 return def_value;
19342         }
19343 }
19344
19345 DUK_INTERNAL const char *duk_get_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
19346         duk_hstring *h;
19347
19348         DUK_ASSERT_API_ENTRY(thr);
19349
19350         h = duk_get_hstring_notsymbol(thr, idx);
19351         if (h) {
19352                 return (const char *) DUK_HSTRING_GET_DATA(h);
19353         } else {
19354                 return NULL;
19355         }
19356 }
19357
19358 DUK_EXTERNAL const char *duk_require_string(duk_hthread *thr, duk_idx_t idx) {
19359         DUK_ASSERT_API_ENTRY(thr);
19360
19361         return duk_require_lstring(thr, idx, NULL);
19362 }
19363
19364 DUK_INTERNAL const char *duk_require_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
19365         duk_hstring *h;
19366
19367         DUK_ASSERT_API_ENTRY(thr);
19368
19369         h = duk_require_hstring_notsymbol(thr, idx);
19370         DUK_ASSERT(h != NULL);
19371         return (const char *) DUK_HSTRING_GET_DATA(h);
19372 }
19373
19374 DUK_EXTERNAL void duk_require_object(duk_hthread *thr, duk_idx_t idx) {
19375         duk_tval *tv;
19376
19377         DUK_ASSERT_API_ENTRY(thr);
19378
19379         tv = duk_get_tval_or_unused(thr, idx);
19380         DUK_ASSERT(tv != NULL);
19381         if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
19382                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
19383                 DUK_WO_NORETURN(return;);
19384         }
19385 }
19386
19387 DUK_LOCAL void *duk__get_pointer_raw(duk_hthread *thr, duk_idx_t idx, void *def_value) {
19388         duk_tval *tv;
19389         void *p;
19390
19391         DUK_ASSERT_CTX_VALID(thr);
19392
19393         tv = duk_get_tval_or_unused(thr, idx);
19394         DUK_ASSERT(tv != NULL);
19395         if (!DUK_TVAL_IS_POINTER(tv)) {
19396                 return def_value;
19397         }
19398
19399         p = DUK_TVAL_GET_POINTER(tv);  /* may be NULL */
19400         return p;
19401 }
19402
19403 DUK_EXTERNAL void *duk_get_pointer(duk_hthread *thr, duk_idx_t idx) {
19404         DUK_ASSERT_API_ENTRY(thr);
19405         return duk__get_pointer_raw(thr, idx, NULL /*def_value*/);
19406 }
19407
19408 DUK_EXTERNAL void *duk_opt_pointer(duk_hthread *thr, duk_idx_t idx, void *def_value) {
19409         DUK_ASSERT_API_ENTRY(thr);
19410
19411         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19412                 return def_value;
19413         }
19414         return duk_require_pointer(thr, idx);
19415 }
19416
19417 DUK_EXTERNAL void *duk_get_pointer_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
19418         DUK_ASSERT_API_ENTRY(thr);
19419         return duk__get_pointer_raw(thr, idx, def_value);
19420 }
19421
19422 DUK_EXTERNAL void *duk_require_pointer(duk_hthread *thr, duk_idx_t idx) {
19423         duk_tval *tv;
19424         void *p;
19425
19426         DUK_ASSERT_API_ENTRY(thr);
19427
19428         /* Note: here we must be wary of the fact that a pointer may be
19429          * valid and be a NULL.
19430          */
19431         tv = duk_get_tval_or_unused(thr, idx);
19432         DUK_ASSERT(tv != NULL);
19433         if (DUK_UNLIKELY(!DUK_TVAL_IS_POINTER(tv))) {
19434                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER);
19435                 DUK_WO_NORETURN(return NULL;);
19436         }
19437         p = DUK_TVAL_GET_POINTER(tv);  /* may be NULL */
19438         return p;
19439 }
19440
19441 #if 0  /*unused*/
19442 DUK_INTERNAL void *duk_get_voidptr(duk_hthread *thr, duk_idx_t idx) {
19443         duk_tval *tv;
19444         duk_heaphdr *h;
19445
19446         DUK_ASSERT_API_ENTRY(thr);
19447
19448         tv = duk_get_tval_or_unused(thr, idx);
19449         DUK_ASSERT(tv != NULL);
19450         if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
19451                 return NULL;
19452         }
19453
19454         h = DUK_TVAL_GET_HEAPHDR(tv);
19455         DUK_ASSERT(h != NULL);
19456         return (void *) h;
19457 }
19458 #endif
19459
19460 DUK_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) {
19461         duk_hbuffer *h;
19462         void *ret;
19463         duk_size_t len;
19464         duk_tval *tv;
19465
19466         DUK_ASSERT_CTX_VALID(thr);
19467
19468         if (out_size != NULL) {
19469                 *out_size = 0;
19470         }
19471
19472         tv = duk_get_tval_or_unused(thr, idx);
19473         DUK_ASSERT(tv != NULL);
19474         if (DUK_LIKELY(DUK_TVAL_IS_BUFFER(tv))) {
19475                 h = DUK_TVAL_GET_BUFFER(tv);
19476                 DUK_ASSERT(h != NULL);
19477
19478                 len = DUK_HBUFFER_GET_SIZE(h);
19479                 ret = DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
19480         } else {
19481                 if (throw_flag) {
19482                         DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
19483                         DUK_WO_NORETURN(return NULL;);
19484                 }
19485                 len = def_size;
19486                 ret = def_ptr;
19487         }
19488
19489         if (out_size != NULL) {
19490                 *out_size = len;
19491         }
19492         return ret;
19493 }
19494
19495 DUK_EXTERNAL void *duk_get_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
19496         DUK_ASSERT_API_ENTRY(thr);
19497
19498         return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/);
19499 }
19500
19501 DUK_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) {
19502         DUK_ASSERT_API_ENTRY(thr);
19503
19504         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19505                 if (out_size != NULL) {
19506                         *out_size = def_size;
19507                 }
19508                 return def_ptr;
19509         }
19510         return duk_require_buffer(thr, idx, out_size);
19511 }
19512
19513 DUK_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) {
19514         DUK_ASSERT_API_ENTRY(thr);
19515
19516         return duk__get_buffer_helper(thr, idx, out_size, def_ptr, def_len, 0 /*throw_flag*/);
19517 }
19518
19519 DUK_EXTERNAL void *duk_require_buffer(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
19520         DUK_ASSERT_API_ENTRY(thr);
19521
19522         return duk__get_buffer_helper(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/);
19523 }
19524
19525 /* Get the active buffer data area for a plain buffer or a buffer object.
19526  * Return NULL if the the value is not a buffer.  Note that a buffer may
19527  * have a NULL data pointer when its size is zero, the optional 'out_isbuffer'
19528  * argument allows caller to detect this reliably.
19529  */
19530 DUK_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) {
19531         duk_tval *tv;
19532
19533         DUK_ASSERT_API_ENTRY(thr);
19534
19535         if (out_isbuffer != NULL) {
19536                 *out_isbuffer = 0;
19537         }
19538         if (out_size != NULL) {
19539                 *out_size = def_size;
19540         }
19541
19542         tv = duk_get_tval_or_unused(thr, idx);
19543         DUK_ASSERT(tv != NULL);
19544
19545         if (DUK_TVAL_IS_BUFFER(tv)) {
19546                 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
19547                 DUK_ASSERT(h != NULL);
19548                 if (out_size != NULL) {
19549                         *out_size = DUK_HBUFFER_GET_SIZE(h);
19550                 }
19551                 if (out_isbuffer != NULL) {
19552                         *out_isbuffer = 1;
19553                 }
19554                 return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);  /* may be NULL (but only if size is 0) */
19555         }
19556 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
19557         else if (DUK_TVAL_IS_OBJECT(tv)) {
19558                 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
19559                 DUK_ASSERT(h != NULL);
19560                 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
19561                         /* XXX: this is probably a useful shared helper: for a
19562                          * duk_hbufobj, get a validated buffer pointer/length.
19563                          */
19564                         duk_hbufobj *h_bufobj = (duk_hbufobj *) h;
19565                         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
19566
19567                         if (h_bufobj->buf != NULL &&
19568                             DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
19569                                 duk_uint8_t *p;
19570
19571                                 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf);
19572                                 if (out_size != NULL) {
19573                                         *out_size = (duk_size_t) h_bufobj->length;
19574                                 }
19575                                 if (out_isbuffer != NULL) {
19576                                         *out_isbuffer = 1;
19577                                 }
19578                                 return (void *) (p + h_bufobj->offset);
19579                         }
19580                         /* if slice not fully valid, treat as error */
19581                 }
19582         }
19583 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
19584
19585         if (throw_flag) {
19586                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
19587                 DUK_WO_NORETURN(return NULL;);
19588         }
19589         return def_ptr;
19590 }
19591
19592 DUK_EXTERNAL void *duk_get_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
19593         DUK_ASSERT_API_ENTRY(thr);
19594         return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 0 /*throw_flag*/, NULL);
19595 }
19596
19597 DUK_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) {
19598         DUK_ASSERT_API_ENTRY(thr);
19599         return duk_get_buffer_data_raw(thr, idx, out_size, def_ptr, def_size, 0 /*throw_flag*/, NULL);
19600 }
19601
19602 DUK_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) {
19603         DUK_ASSERT_API_ENTRY(thr);
19604
19605         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19606                 if (out_size != NULL) {
19607                         *out_size = def_size;
19608                 }
19609                 return def_ptr;
19610         }
19611         return duk_require_buffer_data(thr, idx, out_size);
19612 }
19613
19614 DUK_EXTERNAL void *duk_require_buffer_data(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size) {
19615         DUK_ASSERT_API_ENTRY(thr);
19616         return duk_get_buffer_data_raw(thr, idx, out_size, NULL /*def_ptr*/, 0 /*def_size*/, 1 /*throw_flag*/, NULL);
19617 }
19618
19619 /* Raw helper for getting a value from the stack, checking its tag.
19620  * The tag cannot be a number because numbers don't have an internal
19621  * tag in the packed representation.
19622  */
19623
19624 DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t tag) {
19625         duk_tval *tv;
19626         duk_heaphdr *ret;
19627
19628         DUK_ASSERT_CTX_VALID(thr);
19629
19630         tv = duk_get_tval_or_unused(thr, idx);
19631         DUK_ASSERT(tv != NULL);
19632         if (DUK_TVAL_GET_TAG(tv) != tag) {
19633                 return (duk_heaphdr *) NULL;
19634         }
19635
19636         ret = DUK_TVAL_GET_HEAPHDR(tv);
19637         DUK_ASSERT(ret != NULL);  /* tagged null pointers should never occur */
19638         return ret;
19639
19640 }
19641
19642 DUK_INTERNAL duk_hstring *duk_get_hstring(duk_hthread *thr, duk_idx_t idx) {
19643         DUK_ASSERT_API_ENTRY(thr);
19644         return (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
19645 }
19646
19647 DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
19648         duk_hstring *h;
19649
19650         DUK_ASSERT_API_ENTRY(thr);
19651
19652         h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
19653         if (DUK_UNLIKELY(h && DUK_HSTRING_HAS_SYMBOL(h))) {
19654                 return NULL;
19655         }
19656         return h;
19657 }
19658
19659 DUK_INTERNAL duk_hstring *duk_require_hstring(duk_hthread *thr, duk_idx_t idx) {
19660         duk_hstring *h;
19661
19662         DUK_ASSERT_API_ENTRY(thr);
19663
19664         h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
19665         if (DUK_UNLIKELY(h == NULL)) {
19666                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
19667                 DUK_WO_NORETURN(return NULL;);
19668         }
19669         return h;
19670 }
19671
19672 DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_hthread *thr, duk_idx_t idx) {
19673         duk_hstring *h;
19674
19675         DUK_ASSERT_API_ENTRY(thr);
19676
19677         h = (duk_hstring *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_STRING);
19678         if (DUK_UNLIKELY(h == NULL || DUK_HSTRING_HAS_SYMBOL(h))) {
19679                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "string", DUK_STR_NOT_STRING);
19680                 DUK_WO_NORETURN(return NULL;);
19681         }
19682         return h;
19683 }
19684
19685 DUK_INTERNAL duk_hobject *duk_get_hobject(duk_hthread *thr, duk_idx_t idx) {
19686         DUK_ASSERT_API_ENTRY(thr);
19687         return (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
19688 }
19689
19690 DUK_INTERNAL duk_hobject *duk_require_hobject(duk_hthread *thr, duk_idx_t idx) {
19691         duk_hobject *h;
19692
19693         DUK_ASSERT_API_ENTRY(thr);
19694
19695         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
19696         if (DUK_UNLIKELY(h == NULL)) {
19697                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
19698                 DUK_WO_NORETURN(return NULL;);
19699         }
19700         return h;
19701 }
19702
19703 DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_hthread *thr, duk_idx_t idx) {
19704         DUK_ASSERT_API_ENTRY(thr);
19705         return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
19706 }
19707
19708 DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_hthread *thr, duk_idx_t idx) {
19709         duk_hbuffer *h;
19710
19711         DUK_ASSERT_API_ENTRY(thr);
19712
19713         h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_BUFFER);
19714         if (DUK_UNLIKELY(h == NULL)) {
19715                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
19716                 DUK_WO_NORETURN(return NULL;);
19717         }
19718         return h;
19719 }
19720
19721 DUK_INTERNAL duk_hthread *duk_get_hthread(duk_hthread *thr, duk_idx_t idx) {
19722         duk_hobject *h;
19723
19724         DUK_ASSERT_API_ENTRY(thr);
19725
19726         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
19727         if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_THREAD(h))) {
19728                 h = NULL;
19729         }
19730         return (duk_hthread *) h;
19731 }
19732
19733 DUK_INTERNAL duk_hthread *duk_require_hthread(duk_hthread *thr, duk_idx_t idx) {
19734         duk_hobject *h;
19735
19736         DUK_ASSERT_API_ENTRY(thr);
19737
19738         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
19739         if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_THREAD(h)))) {
19740                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD);
19741                 DUK_WO_NORETURN(return NULL;);
19742         }
19743         return (duk_hthread *) h;
19744 }
19745
19746 DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
19747         duk_hobject *h;
19748
19749         DUK_ASSERT_API_ENTRY(thr);
19750
19751         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
19752         if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h))) {
19753                 h = NULL;
19754         }
19755         return (duk_hcompfunc *) h;
19756 }
19757
19758 DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
19759         duk_hobject *h;
19760
19761         DUK_ASSERT_API_ENTRY(thr);
19762
19763         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
19764         if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h)))) {
19765                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC);
19766                 DUK_WO_NORETURN(return NULL;);
19767         }
19768         return (duk_hcompfunc *) h;
19769 }
19770
19771 DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
19772         duk_hobject *h;
19773
19774         DUK_ASSERT_API_ENTRY(thr);
19775
19776         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
19777         if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_IS_NATFUNC(h))) {
19778                 h = NULL;
19779         }
19780         return (duk_hnatfunc *) h;
19781 }
19782
19783 DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
19784         duk_hobject *h;
19785
19786         DUK_ASSERT_API_ENTRY(thr);
19787
19788         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
19789         if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h)))) {
19790                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
19791                 DUK_WO_NORETURN(return NULL;);
19792         }
19793         return (duk_hnatfunc *) h;
19794 }
19795
19796 DUK_EXTERNAL duk_c_function duk_get_c_function(duk_hthread *thr, duk_idx_t idx) {
19797         duk_tval *tv;
19798         duk_hobject *h;
19799         duk_hnatfunc *f;
19800
19801         DUK_ASSERT_API_ENTRY(thr);
19802
19803         tv = duk_get_tval_or_unused(thr, idx);
19804         DUK_ASSERT(tv != NULL);
19805         if (DUK_UNLIKELY(!DUK_TVAL_IS_OBJECT(tv))) {
19806                 return NULL;
19807         }
19808         h = DUK_TVAL_GET_OBJECT(tv);
19809         DUK_ASSERT(h != NULL);
19810
19811         if (DUK_UNLIKELY(!DUK_HOBJECT_IS_NATFUNC(h))) {
19812                 return NULL;
19813         }
19814         DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h));
19815         f = (duk_hnatfunc *) h;
19816
19817         return f->func;
19818 }
19819
19820 DUK_EXTERNAL duk_c_function duk_opt_c_function(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
19821         DUK_ASSERT_API_ENTRY(thr);
19822
19823         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19824                 return def_value;
19825         }
19826         return duk_require_c_function(thr, idx);
19827 }
19828
19829 DUK_EXTERNAL duk_c_function duk_get_c_function_default(duk_hthread *thr, duk_idx_t idx, duk_c_function def_value) {
19830         duk_c_function ret;
19831
19832         DUK_ASSERT_API_ENTRY(thr);
19833
19834         ret = duk_get_c_function(thr, idx);
19835         if (ret != NULL) {
19836                 return ret;
19837         }
19838
19839         return def_value;
19840 }
19841
19842 DUK_EXTERNAL duk_c_function duk_require_c_function(duk_hthread *thr, duk_idx_t idx) {
19843         duk_c_function ret;
19844
19845         DUK_ASSERT_API_ENTRY(thr);
19846
19847         ret = duk_get_c_function(thr, idx);
19848         if (DUK_UNLIKELY(!ret)) {
19849                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
19850                 DUK_WO_NORETURN(return ret;);
19851         }
19852         return ret;
19853 }
19854
19855 DUK_EXTERNAL void duk_require_function(duk_hthread *thr, duk_idx_t idx) {
19856         DUK_ASSERT_API_ENTRY(thr);
19857         if (DUK_UNLIKELY(!duk_is_function(thr, idx))) {
19858                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "function", DUK_STR_NOT_FUNCTION);
19859                 DUK_WO_NORETURN(return;);
19860         }
19861 }
19862
19863 DUK_INTERNAL void duk_require_constructable(duk_hthread *thr, duk_idx_t idx) {
19864         duk_hobject *h;
19865
19866         DUK_ASSERT_API_ENTRY(thr);
19867
19868         h = duk_require_hobject_accept_mask(thr, idx, DUK_TYPE_MASK_LIGHTFUNC);
19869         if (DUK_UNLIKELY(h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h))) {
19870                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE);
19871                 DUK_WO_NORETURN(return;);
19872         }
19873         /* Lightfuncs (h == NULL) are constructable. */
19874 }
19875
19876 DUK_EXTERNAL duk_hthread *duk_get_context(duk_hthread *thr, duk_idx_t idx) {
19877         DUK_ASSERT_API_ENTRY(thr);
19878
19879         return duk_get_hthread(thr, idx);
19880 }
19881
19882 DUK_EXTERNAL duk_hthread *duk_require_context(duk_hthread *thr, duk_idx_t idx) {
19883         DUK_ASSERT_API_ENTRY(thr);
19884
19885         return duk_require_hthread(thr, idx);
19886 }
19887
19888 DUK_EXTERNAL duk_hthread *duk_opt_context(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
19889         DUK_ASSERT_API_ENTRY(thr);
19890
19891         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19892                 return def_value;
19893         }
19894         return duk_require_context(thr, idx);
19895 }
19896
19897 DUK_EXTERNAL duk_hthread *duk_get_context_default(duk_hthread *thr, duk_idx_t idx, duk_hthread *def_value) {
19898         duk_hthread *ret;
19899
19900         DUK_ASSERT_API_ENTRY(thr);
19901
19902         ret = duk_get_context(thr, idx);
19903         if (ret != NULL) {
19904                 return ret;
19905         }
19906
19907         return def_value;
19908 }
19909
19910 DUK_EXTERNAL void *duk_get_heapptr(duk_hthread *thr, duk_idx_t idx) {
19911         duk_tval *tv;
19912         void *ret;
19913
19914         DUK_ASSERT_API_ENTRY(thr);
19915
19916         tv = duk_get_tval_or_unused(thr, idx);
19917         DUK_ASSERT(tv != NULL);
19918         if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
19919                 return (void *) NULL;
19920         }
19921
19922         ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
19923         DUK_ASSERT(ret != NULL);
19924         return ret;
19925 }
19926
19927 DUK_EXTERNAL void *duk_opt_heapptr(duk_hthread *thr, duk_idx_t idx, void *def_value) {
19928         DUK_ASSERT_API_ENTRY(thr);
19929
19930         if (duk_check_type_mask(thr, idx, DUK_TYPE_MASK_NONE | DUK_TYPE_MASK_UNDEFINED)) {
19931                 return def_value;
19932         }
19933         return duk_require_heapptr(thr, idx);
19934 }
19935
19936 DUK_EXTERNAL void *duk_get_heapptr_default(duk_hthread *thr, duk_idx_t idx, void *def_value) {
19937         void *ret;
19938
19939         DUK_ASSERT_API_ENTRY(thr);
19940
19941         ret = duk_get_heapptr(thr, idx);
19942         if (ret != NULL) {
19943                 return ret;
19944         }
19945
19946         return def_value;
19947 }
19948
19949 DUK_EXTERNAL void *duk_require_heapptr(duk_hthread *thr, duk_idx_t idx) {
19950         duk_tval *tv;
19951         void *ret;
19952
19953         DUK_ASSERT_API_ENTRY(thr);
19954
19955         tv = duk_get_tval_or_unused(thr, idx);
19956         DUK_ASSERT(tv != NULL);
19957         if (DUK_UNLIKELY(!DUK_TVAL_IS_HEAP_ALLOCATED(tv))) {
19958                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE);
19959                 DUK_WO_NORETURN(return NULL;);
19960         }
19961
19962         ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
19963         DUK_ASSERT(ret != NULL);
19964         return ret;
19965 }
19966
19967 /* Internal helper for getting/requiring a duk_hobject with possible promotion. */
19968 DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
19969         duk_uint_t val_mask;
19970         duk_hobject *res;
19971
19972         DUK_ASSERT_CTX_VALID(thr);
19973
19974         res = duk_get_hobject(thr, idx);  /* common case, not promoted */
19975         if (DUK_LIKELY(res != NULL)) {
19976                 DUK_ASSERT(res != NULL);
19977                 return res;
19978         }
19979
19980         val_mask = duk_get_type_mask(thr, idx);
19981         if (val_mask & type_mask) {
19982                 if (type_mask & DUK_TYPE_MASK_PROMOTE) {
19983                         res = duk_to_hobject(thr, idx);
19984                         DUK_ASSERT(res != NULL);
19985                         return res;
19986                 } else {
19987                         return NULL;  /* accept without promoting */
19988                 }
19989         }
19990
19991         if (type_mask & DUK_TYPE_MASK_THROW) {
19992                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "object", DUK_STR_NOT_OBJECT);
19993                 DUK_WO_NORETURN(return NULL;);
19994         }
19995         return NULL;
19996 }
19997
19998 /* Get a duk_hobject * at 'idx'; if the value is not an object but matches the
19999  * supplied 'type_mask', promote it to an object and return the duk_hobject *.
20000  * This is useful for call sites which want an object but also accept a plain
20001  * buffer and/or a lightfunc which gets automatically promoted to an object.
20002  * Return value is NULL if value is neither an object nor a plain type allowed
20003  * by the mask.
20004  */
20005 DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
20006         DUK_ASSERT_API_ENTRY(thr);
20007         return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_PROMOTE);
20008 }
20009
20010 /* Like duk_get_hobject_promote_mask() but throw a TypeError instead of
20011  * returning a NULL.
20012  */
20013 DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
20014         DUK_ASSERT_API_ENTRY(thr);
20015         return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE);
20016 }
20017
20018 /* Require a duk_hobject * at 'idx'; if the value is not an object but matches the
20019  * supplied 'type_mask', return a NULL instead.  Otherwise throw a TypeError.
20020  */
20021 DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t type_mask) {
20022         DUK_ASSERT_API_ENTRY(thr);
20023         return duk__get_hobject_promote_mask_raw(thr, idx, type_mask | DUK_TYPE_MASK_THROW);
20024 }
20025
20026 DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
20027         duk_hobject *h;
20028
20029         DUK_ASSERT_API_ENTRY(thr);
20030         DUK_ASSERT_DISABLE(classnum >= 0);  /* unsigned */
20031         DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
20032
20033         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20034         if (DUK_UNLIKELY(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum)) {
20035                 h = NULL;
20036         }
20037         return h;
20038 }
20039
20040 DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t classnum) {
20041         duk_hobject *h;
20042
20043         DUK_ASSERT_API_ENTRY(thr);
20044         DUK_ASSERT_DISABLE(classnum >= 0);  /* unsigned */
20045         DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
20046
20047         h = (duk_hobject *) duk__get_tagged_heaphdr_raw(thr, idx, DUK_TAG_OBJECT);
20048         if (DUK_UNLIKELY(!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum))) {
20049                 duk_hstring *h_class;
20050                 h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
20051                 DUK_UNREF(h_class);
20052
20053                 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
20054                 DUK_WO_NORETURN(return NULL;);
20055         }
20056         return h;
20057 }
20058
20059 DUK_EXTERNAL duk_size_t duk_get_length(duk_hthread *thr, duk_idx_t idx) {
20060         duk_tval *tv;
20061
20062         DUK_ASSERT_API_ENTRY(thr);
20063
20064         tv = duk_get_tval_or_unused(thr, idx);
20065         DUK_ASSERT(tv != NULL);
20066
20067         switch (DUK_TVAL_GET_TAG(tv)) {
20068         case DUK_TAG_UNDEFINED:
20069         case DUK_TAG_NULL:
20070         case DUK_TAG_BOOLEAN:
20071         case DUK_TAG_POINTER:
20072                 return 0;
20073 #if defined(DUK_USE_PREFER_SIZE)
20074         /* String and buffer have a virtual non-configurable .length property
20075          * which is within size_t range so it can be looked up without specific
20076          * type checks.  Lightfuncs inherit from %NativeFunctionPrototype%
20077          * which provides an inherited .length accessor; it could be overwritten
20078          * to produce unexpected types or values, but just number convert and
20079          * duk_size_t cast for now.
20080          */
20081         case DUK_TAG_STRING:
20082         case DUK_TAG_BUFFER:
20083         case DUK_TAG_LIGHTFUNC: {
20084                 duk_size_t ret;
20085                 duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
20086                 ret = (duk_size_t) duk_to_number_m1(thr);
20087                 duk_pop_unsafe(thr);
20088                 return ret;
20089         }
20090 #else  /* DUK_USE_PREFER_SIZE */
20091         case DUK_TAG_STRING: {
20092                 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
20093                 DUK_ASSERT(h != NULL);
20094                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
20095                         return 0;
20096                 }
20097                 return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
20098         }
20099         case DUK_TAG_BUFFER: {
20100                 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
20101                 DUK_ASSERT(h != NULL);
20102                 return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
20103         }
20104         case DUK_TAG_LIGHTFUNC: {
20105                 /* We could look up the length from the lightfunc duk_tval,
20106                  * but since Duktape 2.2 lightfunc .length comes from
20107                  * %NativeFunctionPrototype% which can be overridden, so
20108                  * look up the property explicitly.
20109                  */
20110                 duk_size_t ret;
20111                 duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
20112                 ret = (duk_size_t) duk_to_number_m1(thr);
20113                 duk_pop_unsafe(thr);
20114                 return ret;
20115         }
20116 #endif  /* DUK_USE_PREFER_SIZE */
20117         case DUK_TAG_OBJECT: {
20118                 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
20119                 DUK_ASSERT(h != NULL);
20120                 return (duk_size_t) duk_hobject_get_length(thr, h);
20121         }
20122 #if defined(DUK_USE_FASTINT)
20123         case DUK_TAG_FASTINT:
20124 #endif
20125         default:
20126                 /* number or 'unused' */
20127                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv) || DUK_TVAL_IS_UNUSED(tv));
20128                 return 0;
20129         }
20130
20131         DUK_UNREACHABLE();
20132 }
20133
20134 /*
20135  *  duk_known_xxx() helpers
20136  *
20137  *  Used internally when we're 100% sure that a certain index is valid and
20138  *  contains an object of a certain type.  For example, if we duk_push_object()
20139  *  we can then safely duk_known_hobject(thr, -1).  These helpers just assert
20140  *  for the index and type, and if the assumptions are not valid, memory unsafe
20141  *  behavior happens.
20142  */
20143
20144 DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_hthread *thr, duk_idx_t idx) {
20145         duk_tval *tv;
20146         duk_heaphdr *h;
20147
20148         DUK_ASSERT_CTX_VALID(thr);
20149         if (idx < 0) {
20150                 tv = thr->valstack_top + idx;
20151         } else {
20152                 tv = thr->valstack_bottom + idx;
20153         }
20154         DUK_ASSERT(tv >= thr->valstack_bottom);
20155         DUK_ASSERT(tv < thr->valstack_top);
20156         h = DUK_TVAL_GET_HEAPHDR(tv);
20157         DUK_ASSERT(h != NULL);
20158         return h;
20159 }
20160
20161 DUK_INTERNAL duk_hstring *duk_known_hstring(duk_hthread *thr, duk_idx_t idx) {
20162         DUK_ASSERT_API_ENTRY(thr);
20163         DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
20164         return (duk_hstring *) duk__known_heaphdr(thr, idx);
20165 }
20166
20167 DUK_INTERNAL duk_hobject *duk_known_hobject(duk_hthread *thr, duk_idx_t idx) {
20168         DUK_ASSERT_API_ENTRY(thr);
20169         DUK_ASSERT(duk_get_hobject(thr, idx) != NULL);
20170         return (duk_hobject *) duk__known_heaphdr(thr, idx);
20171 }
20172
20173 DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_hthread *thr, duk_idx_t idx) {
20174         DUK_ASSERT_API_ENTRY(thr);
20175         DUK_ASSERT(duk_get_hbuffer(thr, idx) != NULL);
20176         return (duk_hbuffer *) duk__known_heaphdr(thr, idx);
20177 }
20178
20179 DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_hthread *thr, duk_idx_t idx) {
20180         DUK_ASSERT_API_ENTRY(thr);
20181         DUK_ASSERT(duk_get_hcompfunc(thr, idx) != NULL);
20182         return (duk_hcompfunc *) duk__known_heaphdr(thr, idx);
20183 }
20184
20185 DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_hthread *thr, duk_idx_t idx) {
20186         DUK_ASSERT_API_ENTRY(thr);
20187         DUK_ASSERT(duk_get_hnatfunc(thr, idx) != NULL);
20188         return (duk_hnatfunc *) duk__known_heaphdr(thr, idx);
20189 }
20190
20191 DUK_EXTERNAL void duk_set_length(duk_hthread *thr, duk_idx_t idx, duk_size_t len) {
20192         DUK_ASSERT_API_ENTRY(thr);
20193
20194         idx = duk_normalize_index(thr, idx);
20195         duk_push_uint(thr, (duk_uint_t) len);
20196         duk_put_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
20197 }
20198
20199 /*
20200  *  Conversions and coercions
20201  *
20202  *  The conversion/coercions are in-place operations on the value stack.
20203  *  Some operations are implemented here directly, while others call a
20204  *  helper in duk_js_ops.c after validating arguments.
20205  */
20206
20207 /* E5 Section 8.12.8 */
20208
20209 DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t func_stridx) {
20210         if (duk_get_prop_stridx(thr, idx, func_stridx)) {
20211                 /* [ ... func ] */
20212                 if (duk_is_callable(thr, -1)) {
20213                         duk_dup(thr, idx);         /* -> [ ... func this ] */
20214                         duk_call_method(thr, 0);     /* -> [ ... retval ] */
20215                         if (duk_is_primitive(thr, -1)) {
20216                                 duk_replace(thr, idx);
20217                                 return 1;
20218                         }
20219                         /* [ ... retval ]; popped below */
20220                 }
20221         }
20222         duk_pop_unsafe(thr);  /* [ ... func/retval ] -> [ ... ] */
20223         return 0;
20224 }
20225
20226 DUK_EXTERNAL void duk_to_undefined(duk_hthread *thr, duk_idx_t idx) {
20227         duk_tval *tv;
20228
20229         DUK_ASSERT_API_ENTRY(thr);
20230
20231         tv = duk_require_tval(thr, idx);
20232         DUK_ASSERT(tv != NULL);
20233         DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);  /* side effects */
20234 }
20235
20236 DUK_EXTERNAL void duk_to_null(duk_hthread *thr, duk_idx_t idx) {
20237         duk_tval *tv;
20238
20239         DUK_ASSERT_API_ENTRY(thr);
20240
20241         tv = duk_require_tval(thr, idx);
20242         DUK_ASSERT(tv != NULL);
20243         DUK_TVAL_SET_NULL_UPDREF(thr, tv);  /* side effects */
20244 }
20245
20246 /* E5 Section 9.1 */
20247 DUK_LOCAL const char * const duk__toprim_hint_strings[3] = {
20248         "default", "string", "number"
20249 };
20250 DUK_LOCAL void duk__to_primitive_helper(duk_hthread *thr, duk_idx_t idx, duk_int_t hint, duk_bool_t check_symbol) {
20251         /* Inline initializer for coercers[] is not allowed by old compilers like BCC. */
20252         duk_small_uint_t coercers[2];
20253
20254         DUK_ASSERT_API_ENTRY(thr);
20255         DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
20256
20257         idx = duk_require_normalize_index(thr, idx);
20258
20259         /* If already primitive, return as is. */
20260         if (!duk_check_type_mask(thr, idx, DUK_TYPE_MASK_OBJECT |
20261                                            DUK_TYPE_MASK_LIGHTFUNC |
20262                                            DUK_TYPE_MASK_BUFFER)) {
20263                 DUK_ASSERT(!duk_is_buffer(thr, idx));  /* duk_to_string() relies on this behavior */
20264                 return;
20265         }
20266
20267         /* @@toPrimitive lookup.  Also do for plain buffers and lightfuncs
20268          * which mimic objects.
20269          */
20270         if (check_symbol && duk_get_method_stridx(thr, idx, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_PRIMITIVE)) {
20271                 DUK_ASSERT(hint >= 0 && (duk_size_t) hint < sizeof(duk__toprim_hint_strings) / sizeof(const char *));
20272                 duk_dup(thr, idx);
20273                 duk_push_string(thr, duk__toprim_hint_strings[hint]);
20274                 duk_call_method(thr, 1);  /* [ ... method value hint ] -> [ ... res] */
20275                 if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
20276                                                  DUK_TYPE_MASK_LIGHTFUNC |
20277                                                  DUK_TYPE_MASK_BUFFER)) {
20278                         goto fail;
20279                 }
20280                 duk_replace(thr, idx);
20281                 return;
20282         }
20283
20284         /* Objects are coerced based on E5 specification.
20285          * Lightfuncs are coerced because they behave like
20286          * objects even if they're internally a primitive
20287          * type.  Same applies to plain buffers, which behave
20288          * like ArrayBuffer objects since Duktape 2.x.
20289          */
20290
20291         /* Hint magic for Date is unnecessary in ES2015 because of
20292          * Date.prototype[@@toPrimitive].  However, it is needed if
20293          * symbol support is not enabled.
20294          */
20295 #if defined(DUK_USE_SYMBOL_BUILTIN)
20296         if (hint == DUK_HINT_NONE) {
20297                 hint = DUK_HINT_NUMBER;
20298         }
20299 #else  /* DUK_USE_SYMBOL_BUILTIN */
20300         if (hint == DUK_HINT_NONE) {
20301                 duk_small_uint_t class_number;
20302
20303                 class_number = duk_get_class_number(thr, idx);
20304                 if (class_number == DUK_HOBJECT_CLASS_DATE) {
20305                         hint = DUK_HINT_STRING;
20306                 } else {
20307                         hint = DUK_HINT_NUMBER;
20308                 }
20309         }
20310 #endif  /* DUK_USE_SYMBOL_BUILTIN */
20311
20312         coercers[0] = DUK_STRIDX_VALUE_OF;
20313         coercers[1] = DUK_STRIDX_TO_STRING;
20314         if (hint == DUK_HINT_STRING) {
20315                 coercers[0] = DUK_STRIDX_TO_STRING;
20316                 coercers[1] = DUK_STRIDX_VALUE_OF;
20317         }
20318
20319         if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[0])) {
20320                 DUK_ASSERT(!duk_is_buffer(thr, idx));  /* duk_to_string() relies on this behavior */
20321                 return;
20322         }
20323
20324         if (duk__defaultvalue_coerce_attempt(thr, idx, coercers[1])) {
20325                 DUK_ASSERT(!duk_is_buffer(thr, idx));  /* duk_to_string() relies on this behavior */
20326                 return;
20327         }
20328
20329  fail:
20330         DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED);
20331         DUK_WO_NORETURN(return;);
20332 }
20333
20334 DUK_EXTERNAL void duk_to_primitive(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
20335         duk__to_primitive_helper(thr, idx, hint, 1 /*check_symbol*/);
20336 }
20337
20338 #if defined(DUK_USE_SYMBOL_BUILTIN)
20339 DUK_INTERNAL void duk_to_primitive_ordinary(duk_hthread *thr, duk_idx_t idx, duk_int_t hint) {
20340         duk__to_primitive_helper(thr, idx, hint, 0 /*check_symbol*/);
20341 }
20342 #endif
20343
20344 /* E5 Section 9.2 */
20345 DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_hthread *thr, duk_idx_t idx) {
20346         duk_tval *tv;
20347         duk_bool_t val;
20348
20349         DUK_ASSERT_API_ENTRY(thr);
20350
20351         idx = duk_require_normalize_index(thr, idx);
20352         tv = DUK_GET_TVAL_POSIDX(thr, idx);
20353         DUK_ASSERT(tv != NULL);
20354
20355         val = duk_js_toboolean(tv);
20356         DUK_ASSERT(val == 0 || val == 1);
20357
20358         /* Note: no need to re-lookup tv, conversion is side effect free. */
20359         DUK_ASSERT(tv != NULL);
20360         DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val);  /* side effects */
20361         return val;
20362 }
20363
20364 DUK_INTERNAL duk_bool_t duk_to_boolean_top_pop(duk_hthread *thr) {
20365         duk_tval *tv;
20366         duk_bool_t val;
20367
20368         DUK_ASSERT_API_ENTRY(thr);
20369
20370         tv = duk_require_tval(thr, -1);
20371         DUK_ASSERT(tv != NULL);
20372
20373         val = duk_js_toboolean(tv);
20374         DUK_ASSERT(val == 0 || val == 1);
20375
20376         duk_pop_unsafe(thr);
20377         return val;
20378 }
20379
20380 DUK_EXTERNAL duk_double_t duk_to_number(duk_hthread *thr, duk_idx_t idx) {
20381         duk_tval *tv;
20382         duk_double_t d;
20383
20384         DUK_ASSERT_API_ENTRY(thr);
20385
20386         /* XXX: No need to normalize; the whole operation could be inlined here to
20387          * avoid 'tv' re-lookup.
20388          */
20389         idx = duk_require_normalize_index(thr, idx);
20390         tv = DUK_GET_TVAL_POSIDX(thr, idx);
20391         DUK_ASSERT(tv != NULL);
20392         d = duk_js_tonumber(thr, tv);  /* XXX: fastint coercion? now result will always be a non-fastint */
20393
20394         /* ToNumber() may have side effects so must relookup 'tv'. */
20395         tv = DUK_GET_TVAL_POSIDX(thr, idx);
20396         DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d);  /* side effects */
20397         return d;
20398 }
20399
20400 DUK_INTERNAL duk_double_t duk_to_number_m1(duk_hthread *thr) {
20401         DUK_ASSERT_API_ENTRY(thr);
20402         return duk_to_number(thr, -1);
20403 }
20404 DUK_INTERNAL duk_double_t duk_to_number_m2(duk_hthread *thr) {
20405         DUK_ASSERT_API_ENTRY(thr);
20406         return duk_to_number(thr, -2);
20407 }
20408
20409 DUK_INTERNAL duk_double_t duk_to_number_tval(duk_hthread *thr, duk_tval *tv) {
20410 #if defined(DUK_USE_PREFER_SIZE)
20411         duk_double_t res;
20412
20413         DUK_ASSERT_API_ENTRY(thr);
20414
20415         duk_push_tval(thr, tv);
20416         res = duk_to_number_m1(thr);
20417         duk_pop_unsafe(thr);
20418         return res;
20419 #else
20420         duk_double_t res;
20421         duk_tval *tv_dst;
20422
20423         DUK_ASSERT_API_ENTRY(thr);
20424         DUK__ASSERT_SPACE();
20425
20426         tv_dst = thr->valstack_top++;
20427         DUK_TVAL_SET_TVAL(tv_dst, tv);
20428         DUK_TVAL_INCREF(thr, tv_dst);  /* decref not necessary */
20429         res = duk_to_number_m1(thr);  /* invalidates tv_dst */
20430
20431         tv_dst = --thr->valstack_top;
20432         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_dst));
20433         DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_dst));  /* plain number */
20434         DUK_TVAL_SET_UNDEFINED(tv_dst);  /* valstack init policy */
20435
20436         return res;
20437 #endif
20438 }
20439
20440 /* XXX: combine all the integer conversions: they share everything
20441  * but the helper function for coercion.
20442  */
20443
20444 typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
20445
20446 DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_hthread *thr, duk_idx_t idx, duk__toint_coercer coerce_func) {
20447         duk_tval *tv;
20448         duk_double_t d;
20449
20450         DUK_ASSERT_CTX_VALID(thr);
20451
20452         tv = duk_require_tval(thr, idx);
20453         DUK_ASSERT(tv != NULL);
20454
20455 #if defined(DUK_USE_FASTINT)
20456         /* If argument is a fastint, guarantee that it remains one.
20457          * There's no downgrade check for other cases.
20458          */
20459         if (DUK_TVAL_IS_FASTINT(tv)) {
20460                 /* XXX: Unnecessary conversion back and forth. */
20461                 return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
20462         }
20463 #endif
20464         d = coerce_func(thr, tv);
20465
20466         /* XXX: fastint? */
20467
20468         /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
20469         tv = duk_require_tval(thr, idx);
20470         DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d);  /* side effects */
20471         return d;
20472 }
20473
20474 DUK_EXTERNAL duk_int_t duk_to_int(duk_hthread *thr, duk_idx_t idx) {
20475         /* Value coercion (in stack): ToInteger(), E5 Section 9.4,
20476          * API return value coercion: custom.
20477          */
20478         DUK_ASSERT_API_ENTRY(thr);
20479         (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
20480         return (duk_int_t) duk__api_coerce_d2i(thr, idx, 0 /*def_value*/, 0 /*require*/);
20481 }
20482
20483 DUK_EXTERNAL duk_uint_t duk_to_uint(duk_hthread *thr, duk_idx_t idx) {
20484         /* Value coercion (in stack): ToInteger(), E5 Section 9.4,
20485          * API return value coercion: custom.
20486          */
20487         DUK_ASSERT_API_ENTRY(thr);
20488         (void) duk__to_int_uint_helper(thr, idx, duk_js_tointeger);
20489         return (duk_uint_t) duk__api_coerce_d2ui(thr, idx, 0 /*def_value*/, 0 /*require*/);
20490 }
20491
20492 DUK_EXTERNAL duk_int32_t duk_to_int32(duk_hthread *thr, duk_idx_t idx) {
20493         duk_tval *tv;
20494         duk_int32_t ret;
20495
20496         DUK_ASSERT_API_ENTRY(thr);
20497
20498         tv = duk_require_tval(thr, idx);
20499         DUK_ASSERT(tv != NULL);
20500         ret = duk_js_toint32(thr, tv);
20501
20502         /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
20503         tv = duk_require_tval(thr, idx);
20504         DUK_TVAL_SET_I32_UPDREF(thr, tv, ret);  /* side effects */
20505         return ret;
20506 }
20507
20508 DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_hthread *thr, duk_idx_t idx) {
20509         duk_tval *tv;
20510         duk_uint32_t ret;
20511
20512         DUK_ASSERT_API_ENTRY(thr);
20513
20514         tv = duk_require_tval(thr, idx);
20515         DUK_ASSERT(tv != NULL);
20516         ret = duk_js_touint32(thr, tv);
20517
20518         /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
20519         tv = duk_require_tval(thr, idx);
20520         DUK_TVAL_SET_U32_UPDREF(thr, tv, ret);  /* side effects */
20521         return ret;
20522 }
20523
20524 DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_hthread *thr, duk_idx_t idx) {
20525         duk_tval *tv;
20526         duk_uint16_t ret;
20527
20528         DUK_ASSERT_API_ENTRY(thr);
20529
20530         tv = duk_require_tval(thr, idx);
20531         DUK_ASSERT(tv != NULL);
20532         ret = duk_js_touint16(thr, tv);
20533
20534         /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
20535         tv = duk_require_tval(thr, idx);
20536         DUK_TVAL_SET_U32_UPDREF(thr, tv, ret);  /* side effects */
20537         return ret;
20538 }
20539
20540 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
20541 /* Special coercion for Uint8ClampedArray. */
20542 DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_hthread *thr, duk_idx_t idx) {
20543         duk_double_t d;
20544         duk_double_t t;
20545         duk_uint8_t ret;
20546
20547         DUK_ASSERT_API_ENTRY(thr);
20548
20549         /* XXX: Simplify this algorithm, should be possible to come up with
20550          * a shorter and faster algorithm by inspecting IEEE representation
20551          * directly.
20552          */
20553
20554         d = duk_to_number(thr, idx);
20555         if (d <= 0.0) {
20556                 return 0;
20557         } else if (d >= 255) {
20558                 return 255;
20559         } else if (DUK_ISNAN(d)) {
20560                 /* Avoid NaN-to-integer coercion as it is compiler specific. */
20561                 return 0;
20562         }
20563
20564         t = d - DUK_FLOOR(d);
20565         if (t == 0.5) {
20566                 /* Exact halfway, round to even. */
20567                 ret = (duk_uint8_t) d;
20568                 ret = (ret + 1) & 0xfe;  /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4
20569                                           * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4
20570                                           */
20571         } else {
20572                 /* Not halfway, round to nearest. */
20573                 ret = (duk_uint8_t) (d + 0.5);
20574         }
20575         return ret;
20576 }
20577 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
20578
20579 DUK_EXTERNAL const char *duk_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
20580         DUK_ASSERT_API_ENTRY(thr);
20581
20582         (void) duk_to_string(thr, idx);
20583         DUK_ASSERT(duk_is_string(thr, idx));
20584         return duk_require_lstring(thr, idx, out_len);
20585 }
20586
20587 DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_hthread *thr, void *udata) {
20588         DUK_ASSERT_CTX_VALID(thr);
20589         DUK_UNREF(udata);
20590
20591         duk_to_string(thr, -1);
20592         return 1;
20593 }
20594
20595 DUK_EXTERNAL const char *duk_safe_to_lstring(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_len) {
20596         DUK_ASSERT_API_ENTRY(thr);
20597
20598         idx = duk_require_normalize_index(thr, idx);
20599
20600         /* We intentionally ignore the duk_safe_call() return value and only
20601          * check the output type.  This way we don't also need to check that
20602          * the returned value is indeed a string in the success case.
20603          */
20604
20605         duk_dup(thr, idx);
20606         (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
20607         if (!duk_is_string(thr, -1)) {
20608                 /* Error: try coercing error to string once. */
20609                 (void) duk_safe_call(thr, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
20610                 if (!duk_is_string(thr, -1)) {
20611                         /* Double error */
20612                         duk_pop_unsafe(thr);
20613                         duk_push_hstring_stridx(thr, DUK_STRIDX_UC_ERROR);
20614                 } else {
20615                         ;
20616                 }
20617         } else {
20618                 /* String; may be a symbol, accepted. */
20619                 ;
20620         }
20621         DUK_ASSERT(duk_is_string(thr, -1));
20622
20623         duk_replace(thr, idx);
20624         DUK_ASSERT(duk_get_string(thr, idx) != NULL);
20625         return duk_get_lstring(thr, idx, out_len);
20626 }
20627
20628 DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_hthread *thr, duk_idx_t idx) {
20629         duk_hstring *h;
20630
20631         DUK_ASSERT_API_ENTRY(thr);
20632
20633         duk_to_primitive(thr, idx, DUK_HINT_STRING);  /* needed for e.g. Symbol objects */
20634         h = duk_get_hstring(thr, idx);
20635         if (h == NULL) {
20636                 /* The "is string?" check may seem unnecessary, but as things
20637                  * are duk_to_hstring() invokes ToString() which fails for
20638                  * symbols.  But since symbols are already strings for Duktape
20639                  * C API, we check for that before doing the coercion.
20640                  */
20641                 h = duk_to_hstring(thr, idx);
20642         }
20643         DUK_ASSERT(h != NULL);
20644         return h;
20645 }
20646
20647 #if defined(DUK_USE_DEBUGGER_SUPPORT)  /* only needed by debugger for now */
20648 DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_hthread *thr, duk_idx_t idx) {
20649         DUK_ASSERT_API_ENTRY(thr);
20650
20651         (void) duk_safe_to_string(thr, idx);
20652         DUK_ASSERT(duk_is_string(thr, idx));
20653         DUK_ASSERT(duk_get_hstring(thr, idx) != NULL);
20654         return duk_known_hstring(thr, idx);
20655 }
20656 #endif
20657
20658 /* Push Object.prototype.toString() output for 'tv'. */
20659 #if 0  /* See XXX note why this variant doesn't work. */
20660 DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects) {
20661         duk_uint_t stridx_bidx = 0;  /* (prototype_bidx << 16) + default_tag_stridx */
20662
20663         DUK_ASSERT_API_ENTRY(thr);
20664
20665         /* Conceptually for any non-undefined/null value we should do a
20666          * ToObject() coercion and look up @@toStringTag (from the object
20667          * prototype) to see if a custom tag should be used.  Avoid the
20668          * actual conversion by doing a prototype lookup without the object
20669          * coercion.  However, see problem below.
20670          */
20671
20672         duk_push_literal(thr, "[object ");  /* -> [ ... "[object" ] */
20673
20674         switch (DUK_TVAL_GET_TAG(tv)) {
20675         case DUK_TAG_UNUSED:  /* Treat like 'undefined', shouldn't happen. */
20676         case DUK_TAG_UNDEFINED: {
20677                 stridx_bidx = DUK_STRIDX_UC_UNDEFINED;
20678                 goto use_stridx;
20679         }
20680         case DUK_TAG_NULL: {
20681                 stridx_bidx = DUK_STRIDX_UC_NULL;
20682                 goto use_stridx;
20683         }
20684         case DUK_TAG_BOOLEAN: {
20685                 stridx_bidx = (DUK_BIDX_BOOLEAN_PROTOTYPE << 16) + DUK_STRIDX_UC_BOOLEAN;
20686                 goto use_proto_bidx;
20687         }
20688         case DUK_TAG_POINTER: {
20689                 stridx_bidx = (DUK_BIDX_POINTER_PROTOTYPE << 16) + DUK_STRIDX_UC_POINTER;
20690                 goto use_proto_bidx;
20691         }
20692         case DUK_TAG_LIGHTFUNC: {
20693                 stridx_bidx = (DUK_BIDX_FUNCTION_PROTOTYPE << 16) + DUK_STRIDX_UC_FUNCTION;
20694                 goto use_proto_bidx;
20695         }
20696         case DUK_TAG_STRING: {
20697                 duk_hstring *h;
20698                 h = DUK_TVAL_GET_STRING(tv);
20699                 DUK_ASSERT(h != NULL);
20700                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
20701                         /* Even without DUK_USE_SYMBOL_BUILTIN the Symbol
20702                          * prototype exists so we can lookup @@toStringTag
20703                          * and provide [object Symbol] for symbol values
20704                          * created from C code.
20705                          */
20706                         stridx_bidx = (DUK_BIDX_SYMBOL_PROTOTYPE << 16) + DUK_STRIDX_UC_SYMBOL;
20707                 } else {
20708                         stridx_bidx = (DUK_BIDX_STRING_PROTOTYPE << 16) + DUK_STRIDX_UC_STRING;
20709                 }
20710                 goto use_proto_bidx;
20711         }
20712         case DUK_TAG_OBJECT: {
20713                 duk_push_tval(thr, tv);
20714                 stridx_bidx = 0xffffffffUL;  /* Marker value. */
20715                 goto use_pushed_object;
20716         }
20717         case DUK_TAG_BUFFER: {
20718                 stridx_bidx = (DUK_BIDX_UINT8ARRAY_PROTOTYPE << 16) + DUK_STRIDX_UINT8_ARRAY;
20719                 goto use_proto_bidx;
20720         }
20721 #if defined(DUK_USE_FASTINT)
20722         case DUK_TAG_FASTINT:
20723                 /* Fall through to generic number case. */
20724 #endif
20725         default: {
20726                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));  /* number (maybe fastint) */
20727                 stridx_bidx = (DUK_BIDX_NUMBER_PROTOTYPE << 16) + DUK_STRIDX_UC_NUMBER;
20728                 goto use_proto_bidx;
20729         }
20730         }
20731         DUK_ASSERT(0);  /* Never here. */
20732
20733  use_proto_bidx:
20734         DUK_ASSERT_BIDX_VALID((stridx_bidx >> 16) & 0xffffUL);
20735         duk_push_hobject(thr, thr->builtins[(stridx_bidx >> 16) & 0xffffUL]);
20736         /* Fall through. */
20737
20738  use_pushed_object:
20739         /* [ ... "[object" obj ] */
20740
20741 #if defined(DUK_USE_SYMBOL_BUILTIN)
20742         /* XXX: better handling with avoid_side_effects == 1; lookup tval
20743          * without Proxy or getter side effects, and use it in sanitized
20744          * form if it's a string.
20745          */
20746         if (!avoid_side_effects) {
20747                 /* XXX: The problem with using the prototype object as the
20748                  * lookup base is that if @@toStringTag is a getter, its
20749                  * 'this' binding must be the ToObject() coerced input value,
20750                  * not the prototype object of the type.
20751                  */
20752                 (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG);
20753                 if (duk_is_string_notsymbol(thr, -1)) {
20754                         duk_remove_m2(thr);
20755                         goto finish;
20756                 }
20757                 duk_pop_unsafe(thr);
20758         }
20759 #endif
20760
20761         if (stridx_bidx == 0xffffffffUL) {
20762                 duk_hobject *h_obj;
20763                 duk_small_uint_t classnum;
20764
20765                 h_obj = duk_known_hobject(thr, -1);
20766                 DUK_ASSERT(h_obj != NULL);
20767                 classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
20768                 stridx_bidx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
20769         } else {
20770                 /* stridx_bidx already has the desired fallback stridx. */
20771                 ;
20772         }
20773         duk_pop_unsafe(thr);
20774         /* Fall through. */
20775
20776  use_stridx:
20777         /* [ ... "[object" ] */
20778         duk_push_hstring_stridx(thr, stridx_bidx & 0xffffUL);
20779
20780  finish:
20781         /* [ ... "[object" tag ] */
20782         duk_push_literal(thr, "]");
20783         duk_concat(thr, 3);  /* [ ... "[object" tag "]" ] -> [ ... res ] */
20784 }
20785 #endif  /* 0 */
20786
20787 DUK_INTERNAL void duk_push_class_string_tval(duk_hthread *thr, duk_tval *tv, duk_bool_t avoid_side_effects) {
20788         duk_hobject *h_obj;
20789         duk_small_uint_t classnum;
20790         duk_small_uint_t stridx;
20791         duk_tval tv_tmp;
20792
20793         DUK_ASSERT_API_ENTRY(thr);
20794         DUK_ASSERT(tv != NULL);
20795
20796         /* Stabilize 'tv', duk_push_literal() may trigger side effects. */
20797         DUK_TVAL_SET_TVAL(&tv_tmp, tv);
20798         tv = &tv_tmp;
20799
20800         /* Conceptually for any non-undefined/null value we should do a
20801          * ToObject() coercion and look up @@toStringTag (from the object
20802          * prototype) to see if a custom result should be used.  We'd like to
20803          * avoid the actual conversion, but even for primitive types the
20804          * prototype may have @@toStringTag.  What's worse, the @@toStringTag
20805          * property may be a getter that must get the object coerced value
20806          * (not the prototype) as its 'this' binding.
20807          *
20808          * For now, do an actual object coercion.  This could be avoided by
20809          * doing a side effect free lookup to see if a getter would be invoked.
20810          * If not, the value can be read directly and the object coercion could
20811          * be avoided.  This may not be worth it in practice, because
20812          * Object.prototype.toString() is usually not performance critical.
20813          */
20814
20815         duk_push_literal(thr, "[object ");  /* -> [ ... "[object" ] */
20816
20817         switch (DUK_TVAL_GET_TAG(tv)) {
20818         case DUK_TAG_UNUSED:  /* Treat like 'undefined', shouldn't happen. */
20819         case DUK_TAG_UNDEFINED: {
20820                 duk_push_hstring_stridx(thr, DUK_STRIDX_UC_UNDEFINED);
20821                 goto finish;
20822         }
20823         case DUK_TAG_NULL: {
20824                 duk_push_hstring_stridx(thr, DUK_STRIDX_UC_NULL);
20825                 goto finish;
20826         }
20827         }
20828
20829         duk_push_tval(thr, tv);
20830         tv = NULL;  /* Invalidated by ToObject(). */
20831         duk_to_object(thr, -1);
20832
20833         /* [ ... "[object" obj ] */
20834
20835 #if defined(DUK_USE_SYMBOL_BUILTIN)
20836         /* XXX: better handling with avoid_side_effects == 1; lookup tval
20837          * without Proxy or getter side effects, and use it in sanitized
20838          * form if it's a string.
20839          */
20840         if (!avoid_side_effects) {
20841                 (void) duk_get_prop_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_TO_STRING_TAG);
20842                 if (duk_is_string_notsymbol(thr, -1)) {
20843                         duk_remove_m2(thr);
20844                         goto finish;
20845                 }
20846                 duk_pop_unsafe(thr);
20847         }
20848 #else
20849         DUK_UNREF(avoid_side_effects);
20850 #endif
20851
20852         h_obj = duk_known_hobject(thr, -1);
20853         DUK_ASSERT(h_obj != NULL);
20854         classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
20855         stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
20856         duk_pop_unsafe(thr);
20857         duk_push_hstring_stridx(thr, stridx);
20858
20859  finish:
20860         /* [ ... "[object" tag ] */
20861         duk_push_literal(thr, "]");
20862         duk_concat(thr, 3);  /* [ ... "[object" tag "]" ] -> [ ... res ] */
20863 }
20864
20865 /* XXX: other variants like uint, u32 etc */
20866 DUK_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) {
20867         duk_tval *tv;
20868         duk_tval tv_tmp;
20869         duk_double_t d, dmin, dmax;
20870         duk_int_t res;
20871         duk_bool_t clamped = 0;
20872
20873         DUK_ASSERT_API_ENTRY(thr);
20874
20875         tv = duk_require_tval(thr, idx);
20876         DUK_ASSERT(tv != NULL);
20877         d = duk_js_tointeger(thr, tv);  /* E5 Section 9.4, ToInteger() */
20878
20879         dmin = (duk_double_t) minval;
20880         dmax = (duk_double_t) maxval;
20881
20882         if (d < dmin) {
20883                 clamped = 1;
20884                 res = minval;
20885                 d = dmin;
20886         } else if (d > dmax) {
20887                 clamped = 1;
20888                 res = maxval;
20889                 d = dmax;
20890         } else {
20891                 res = (duk_int_t) d;
20892         }
20893         DUK_UNREF(d);  /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */
20894         /* 'd' and 'res' agree here */
20895
20896         /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
20897         tv = duk_get_tval(thr, idx);
20898         DUK_ASSERT(tv != NULL);  /* not popped by side effect */
20899         DUK_TVAL_SET_TVAL(&tv_tmp, tv);
20900 #if defined(DUK_USE_FASTINT)
20901 #if (DUK_INT_MAX <= 0x7fffffffL)
20902         DUK_TVAL_SET_I32(tv, res);
20903 #else
20904         /* Clamping needed if duk_int_t is 64 bits. */
20905         if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) {
20906                 DUK_TVAL_SET_FASTINT(tv, res);
20907         } else {
20908                 DUK_TVAL_SET_NUMBER(tv, d);
20909         }
20910 #endif
20911 #else
20912         DUK_TVAL_SET_NUMBER(tv, d);  /* no need to incref */
20913 #endif
20914         DUK_TVAL_DECREF(thr, &tv_tmp);  /* side effects */
20915
20916         if (out_clamped) {
20917                 *out_clamped = clamped;
20918         } else {
20919                 /* coerced value is updated to value stack even when RangeError thrown */
20920                 if (clamped) {
20921                         DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE);
20922                         DUK_WO_NORETURN(return 0;);
20923                 }
20924         }
20925
20926         return res;
20927 }
20928
20929 DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_hthread *thr, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) {
20930         duk_bool_t dummy;
20931
20932         DUK_ASSERT_API_ENTRY(thr);
20933
20934         return duk_to_int_clamped_raw(thr, idx, minval, maxval, &dummy);
20935 }
20936
20937 DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_hthread *thr, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) {
20938         DUK_ASSERT_API_ENTRY(thr);
20939         return duk_to_int_clamped_raw(thr, idx, minval, maxval, NULL);  /* out_clamped==NULL -> RangeError if outside range */
20940 }
20941
20942 DUK_EXTERNAL const char *duk_to_string(duk_hthread *thr, duk_idx_t idx) {
20943         duk_tval *tv;
20944
20945         DUK_ASSERT_API_ENTRY(thr);
20946
20947         idx = duk_require_normalize_index(thr, idx);
20948         tv = DUK_GET_TVAL_POSIDX(thr, idx);
20949         DUK_ASSERT(tv != NULL);
20950
20951         switch (DUK_TVAL_GET_TAG(tv)) {
20952         case DUK_TAG_UNDEFINED: {
20953                 duk_push_hstring_stridx(thr, DUK_STRIDX_LC_UNDEFINED);
20954                 break;
20955         }
20956         case DUK_TAG_NULL: {
20957                 duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
20958                 break;
20959         }
20960         case DUK_TAG_BOOLEAN: {
20961                 if (DUK_TVAL_GET_BOOLEAN(tv)) {
20962                         duk_push_hstring_stridx(thr, DUK_STRIDX_TRUE);
20963                 } else {
20964                         duk_push_hstring_stridx(thr, DUK_STRIDX_FALSE);
20965                 }
20966                 break;
20967         }
20968         case DUK_TAG_STRING: {
20969                 /* Nop for actual strings, TypeError for Symbols.
20970                  * Because various internals rely on ToString() coercion of
20971                  * internal strings, -allow- (NOP) string coercion for hidden
20972                  * symbols.
20973                  */
20974 #if 1
20975                 duk_hstring *h;
20976                 h = DUK_TVAL_GET_STRING(tv);
20977                 DUK_ASSERT(h != NULL);
20978                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
20979                         DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_STRING_COERCE_SYMBOL);
20980                         DUK_WO_NORETURN(goto skip_replace;);
20981                 } else {
20982                         goto skip_replace;
20983                 }
20984 #else
20985                 goto skip_replace;
20986 #endif
20987                 break;
20988         }
20989         case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */
20990         case DUK_TAG_OBJECT: {
20991                 /* Plain buffers: go through ArrayBuffer.prototype.toString()
20992                  * for coercion.
20993                  *
20994                  * Symbol objects: duk_to_primitive() results in a plain symbol
20995                  * value, and duk_to_string() then causes a TypeError.
20996                  */
20997                 duk_to_primitive(thr, idx, DUK_HINT_STRING);
20998                 DUK_ASSERT(!duk_is_buffer(thr, idx));  /* ToPrimitive() must guarantee */
20999                 DUK_ASSERT(!duk_is_object(thr, idx));
21000                 return duk_to_string(thr, idx);  /* Note: recursive call */
21001         }
21002         case DUK_TAG_POINTER: {
21003                 void *ptr = DUK_TVAL_GET_POINTER(tv);
21004                 if (ptr != NULL) {
21005                         duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) ptr);
21006                 } else {
21007                         /* Represent a null pointer as 'null' to be consistent with
21008                          * the JX format variant.  Native '%p' format for a NULL
21009                          * pointer may be e.g. '(nil)'.
21010                          */
21011                         duk_push_hstring_stridx(thr, DUK_STRIDX_LC_NULL);
21012                 }
21013                 break;
21014         }
21015         case DUK_TAG_LIGHTFUNC: {
21016                 /* Should match Function.prototype.toString() */
21017                 duk_push_lightfunc_tostring(thr, tv);
21018                 break;
21019         }
21020 #if defined(DUK_USE_FASTINT)
21021         case DUK_TAG_FASTINT:
21022 #endif
21023         default: {
21024                 /* number */
21025                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21026                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21027                 duk_push_tval(thr, tv);
21028                 duk_numconv_stringify(thr,
21029                                       10 /*radix*/,
21030                                       0 /*precision:shortest*/,
21031                                       0 /*force_exponential*/);
21032                 break;
21033         }
21034         }
21035
21036         duk_replace(thr, idx);
21037
21038  skip_replace:
21039         DUK_ASSERT(duk_is_string(thr, idx));
21040         return duk_require_string(thr, idx);
21041 }
21042
21043 DUK_INTERNAL duk_hstring *duk_to_hstring(duk_hthread *thr, duk_idx_t idx) {
21044         duk_hstring *ret;
21045
21046         DUK_ASSERT_API_ENTRY(thr);
21047
21048         duk_to_string(thr, idx);
21049         ret = duk_get_hstring(thr, idx);
21050         DUK_ASSERT(ret != NULL);
21051         return ret;
21052 }
21053
21054 DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_hthread *thr) {
21055         DUK_ASSERT_API_ENTRY(thr);
21056         return duk_to_hstring(thr, -1);
21057 }
21058
21059 DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_hthread *thr, duk_idx_t idx) {
21060         duk_hstring *ret;
21061
21062         DUK_ASSERT_API_ENTRY(thr);
21063
21064         ret = duk_get_hstring(thr, idx);
21065         if (DUK_UNLIKELY(ret && DUK_HSTRING_HAS_SYMBOL(ret))) {
21066                 return ret;
21067         }
21068         return duk_to_hstring(thr, idx);
21069 }
21070
21071 /* Convert a plain buffer or any buffer object into a string, using the buffer
21072  * bytes 1:1 in the internal string representation.  For views the active byte
21073  * slice (not element slice interpreted as an initializer) is used.  This is
21074  * necessary in Duktape 2.x because ToString(plainBuffer) no longer creates a
21075  * string with the same bytes as in the buffer but rather (usually)
21076  * '[object ArrayBuffer]'.
21077  */
21078 DUK_EXTERNAL const char *duk_buffer_to_string(duk_hthread *thr, duk_idx_t idx) {
21079         void *ptr_src;
21080         duk_size_t len;
21081         const char *res;
21082
21083         DUK_ASSERT_API_ENTRY(thr);
21084
21085         idx = duk_require_normalize_index(thr, idx);
21086
21087         ptr_src = duk_require_buffer_data(thr, idx, &len);
21088         DUK_ASSERT(ptr_src != NULL || len == 0);
21089
21090         res = duk_push_lstring(thr, (const char *) ptr_src, len);
21091         duk_replace(thr, idx);
21092         return res;
21093 }
21094
21095 DUK_EXTERNAL void *duk_to_buffer_raw(duk_hthread *thr, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) {
21096         duk_hbuffer *h_buf;
21097         const duk_uint8_t *src_data;
21098         duk_size_t src_size;
21099         duk_uint8_t *dst_data;
21100
21101         DUK_ASSERT_API_ENTRY(thr);
21102
21103         idx = duk_require_normalize_index(thr, idx);
21104
21105         h_buf = duk_get_hbuffer(thr, idx);
21106         if (h_buf != NULL) {
21107                 /* Buffer is kept as is, with the fixed/dynamic nature of the
21108                  * buffer only changed if requested.  An external buffer
21109                  * is converted into a non-external dynamic buffer in a
21110                  * duk_to_dynamic_buffer() call.
21111                  */
21112                 duk_uint_t tmp;
21113                 duk_uint8_t *tmp_ptr;
21114
21115                 tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf);
21116                 src_data = (const duk_uint8_t *) tmp_ptr;
21117                 src_size = DUK_HBUFFER_GET_SIZE(h_buf);
21118
21119                 tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED);
21120                 if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) ||
21121                     mode == DUK_BUF_MODE_DONTCARE) {
21122                         /* Note: src_data may be NULL if input is a zero-size
21123                          * dynamic buffer.
21124                          */
21125                         dst_data = tmp_ptr;
21126                         goto skip_copy;
21127                 }
21128         } else {
21129                 /* Non-buffer value is first ToString() coerced, then converted
21130                  * to a buffer (fixed buffer is used unless a dynamic buffer is
21131                  * explicitly requested).  Symbols are rejected with a TypeError.
21132                  * XXX: C API could maybe allow symbol-to-buffer coercion?
21133                  */
21134                 src_data = (const duk_uint8_t *) duk_to_lstring(thr, idx, &src_size);
21135         }
21136
21137         dst_data = (duk_uint8_t *) duk_push_buffer(thr, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
21138         /* dst_data may be NULL if size is zero. */
21139         duk_memcpy_unsafe((void *) dst_data, (const void *) src_data, (size_t) src_size);
21140
21141         duk_replace(thr, idx);
21142  skip_copy:
21143
21144         if (out_size) {
21145                 *out_size = src_size;
21146         }
21147         return dst_data;
21148 }
21149
21150 DUK_EXTERNAL void *duk_to_pointer(duk_hthread *thr, duk_idx_t idx) {
21151         duk_tval *tv;
21152         void *res;
21153
21154         DUK_ASSERT_API_ENTRY(thr);
21155
21156         idx = duk_require_normalize_index(thr, idx);
21157         tv = DUK_GET_TVAL_POSIDX(thr, idx);
21158         DUK_ASSERT(tv != NULL);
21159
21160         switch (DUK_TVAL_GET_TAG(tv)) {
21161         case DUK_TAG_UNDEFINED:
21162         case DUK_TAG_NULL:
21163         case DUK_TAG_BOOLEAN:
21164                 res = NULL;
21165                 break;
21166         case DUK_TAG_POINTER:
21167                 res = DUK_TVAL_GET_POINTER(tv);
21168                 break;
21169         case DUK_TAG_STRING:
21170         case DUK_TAG_OBJECT:
21171         case DUK_TAG_BUFFER:
21172                 /* Heap allocated: return heap pointer which is NOT useful
21173                  * for the caller, except for debugging.
21174                  */
21175                 res = (void *) DUK_TVAL_GET_HEAPHDR(tv);
21176                 break;
21177         case DUK_TAG_LIGHTFUNC:
21178                 /* Function pointers do not always cast correctly to void *
21179                  * (depends on memory and segmentation model for instance),
21180                  * so they coerce to NULL.
21181                  */
21182                 res = NULL;
21183                 break;
21184 #if defined(DUK_USE_FASTINT)
21185         case DUK_TAG_FASTINT:
21186 #endif
21187         default:
21188                 /* number */
21189                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21190                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21191                 res = NULL;
21192                 break;
21193         }
21194
21195         duk_push_pointer(thr, res);
21196         duk_replace(thr, idx);
21197         return res;
21198 }
21199
21200 DUK_LOCAL void duk__push_func_from_lightfunc(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
21201         duk_idx_t nargs;
21202         duk_uint_t flags = 0;   /* shared flags for a subset of types */
21203         duk_small_uint_t lf_len;
21204         duk_hnatfunc *nf;
21205
21206         nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
21207         if (nargs == DUK_LFUNC_NARGS_VARARGS) {
21208                 nargs = (duk_idx_t) DUK_VARARGS;
21209         }
21210
21211         flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21212                 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
21213                 DUK_HOBJECT_FLAG_CALLABLE |
21214                 DUK_HOBJECT_FLAG_FASTREFS |
21215                 DUK_HOBJECT_FLAG_NATFUNC |
21216                 DUK_HOBJECT_FLAG_NEWENV |
21217                 DUK_HOBJECT_FLAG_STRICT |
21218                 DUK_HOBJECT_FLAG_NOTAIL |
21219                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
21220         (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
21221
21222         lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
21223         if ((duk_idx_t) lf_len != nargs) {
21224                 /* Explicit length is only needed if it differs from 'nargs'. */
21225                 duk_push_int(thr, (duk_int_t) lf_len);
21226                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
21227         }
21228
21229 #if defined(DUK_USE_FUNC_NAME_PROPERTY)
21230         duk_push_lightfunc_name_raw(thr, func, lf_flags);
21231         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
21232 #endif
21233
21234         nf = duk_known_hnatfunc(thr, -1);
21235         nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
21236 }
21237
21238 DUK_EXTERNAL void duk_to_object(duk_hthread *thr, duk_idx_t idx) {
21239         duk_tval *tv;
21240         duk_uint_t flags = 0;   /* shared flags for a subset of types */
21241         duk_small_int_t proto = 0;
21242
21243         DUK_ASSERT_API_ENTRY(thr);
21244
21245         idx = duk_require_normalize_index(thr, idx);
21246         tv = DUK_GET_TVAL_POSIDX(thr, idx);
21247         DUK_ASSERT(tv != NULL);
21248
21249         switch (DUK_TVAL_GET_TAG(tv)) {
21250 #if !defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21251         case DUK_TAG_BUFFER:  /* With no bufferobject support, don't object coerce. */
21252 #endif
21253         case DUK_TAG_UNDEFINED:
21254         case DUK_TAG_NULL: {
21255                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
21256                 DUK_WO_NORETURN(return;);
21257                 break;
21258         }
21259         case DUK_TAG_BOOLEAN: {
21260                 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21261                         DUK_HOBJECT_FLAG_FASTREFS |
21262                         DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
21263                 proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
21264                 goto create_object;
21265         }
21266         case DUK_TAG_STRING: {
21267                 duk_hstring *h;
21268                 h = DUK_TVAL_GET_STRING(tv);
21269                 DUK_ASSERT(h != NULL);
21270                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
21271                         flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21272                                 DUK_HOBJECT_FLAG_FASTREFS |
21273                                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL);
21274                         proto = DUK_BIDX_SYMBOL_PROTOTYPE;
21275                 } else {
21276                         flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21277                                 DUK_HOBJECT_FLAG_FASTREFS |
21278                                 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
21279                                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
21280                         proto = DUK_BIDX_STRING_PROTOTYPE;
21281                 }
21282                 goto create_object;
21283         }
21284         case DUK_TAG_OBJECT: {
21285                 /* nop */
21286                 break;
21287         }
21288 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21289         case DUK_TAG_BUFFER: {
21290                 /* A plain buffer object coerces to a full ArrayBuffer which
21291                  * is not fully transparent behavior (ToObject() should be a
21292                  * nop for an object).  This behavior matches lightfuncs which
21293                  * also coerce to an equivalent Function object.  There are
21294                  * also downsides to defining ToObject(plainBuffer) as a no-op;
21295                  * for example duk_to_hobject() could result in a NULL pointer.
21296                  */
21297                 duk_hbuffer *h_buf;
21298
21299                 h_buf = DUK_TVAL_GET_BUFFER(tv);
21300                 DUK_ASSERT(h_buf != NULL);
21301                 duk_hbufobj_push_uint8array_from_plain(thr, h_buf);
21302                 goto replace_value;
21303         }
21304 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
21305         case DUK_TAG_POINTER: {
21306                 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21307                         DUK_HOBJECT_FLAG_FASTREFS |
21308                         DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
21309                 proto = DUK_BIDX_POINTER_PROTOTYPE;
21310                 goto create_object;
21311         }
21312         case DUK_TAG_LIGHTFUNC: {
21313                 /* Lightfunc coerces to a Function instance with concrete
21314                  * properties.  Since 'length' is virtual for Duktape/C
21315                  * functions, don't need to define that.  The result is made
21316                  * extensible to mimic what happens to strings in object
21317                  * coercion:
21318                  *
21319                  *   > Object.isExtensible(Object('foo'))
21320                  *   true
21321                  */
21322                 duk_small_uint_t lf_flags;
21323                 duk_c_function func;
21324
21325                 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
21326                 duk__push_func_from_lightfunc(thr, func, lf_flags);
21327                 goto replace_value;
21328         }
21329 #if defined(DUK_USE_FASTINT)
21330         case DUK_TAG_FASTINT:
21331 #endif
21332         default: {
21333                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21334                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21335                 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
21336                         DUK_HOBJECT_FLAG_FASTREFS |
21337                         DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
21338                 proto = DUK_BIDX_NUMBER_PROTOTYPE;
21339                 goto create_object;
21340         }
21341         }
21342         DUK_ASSERT(duk_is_object(thr, idx));
21343         return;
21344
21345  create_object:
21346         (void) duk_push_object_helper(thr, flags, proto);
21347
21348         /* Note: Boolean prototype's internal value property is not writable,
21349          * but duk_xdef_prop_stridx() disregards the write protection.  Boolean
21350          * instances are immutable.
21351          *
21352          * String and buffer special behaviors are already enabled which is not
21353          * ideal, but a write to the internal value is not affected by them.
21354          */
21355         duk_dup(thr, idx);
21356         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
21357
21358  replace_value:
21359         duk_replace(thr, idx);
21360         DUK_ASSERT(duk_is_object(thr, idx));
21361 }
21362
21363 DUK_INTERNAL duk_hobject *duk_to_hobject(duk_hthread *thr, duk_idx_t idx) {
21364         duk_hobject *ret;
21365
21366         DUK_ASSERT_API_ENTRY(thr);
21367
21368         duk_to_object(thr, idx);
21369         ret = duk_known_hobject(thr, idx);
21370         return ret;
21371 }
21372
21373 /*
21374  *  Type checking
21375  */
21376
21377 DUK_LOCAL duk_bool_t duk__tag_check(duk_hthread *thr, duk_idx_t idx, duk_small_uint_t tag) {
21378         duk_tval *tv;
21379
21380         tv = duk_get_tval_or_unused(thr, idx);
21381         DUK_ASSERT(tv != NULL);
21382         return (DUK_TVAL_GET_TAG(tv) == tag);
21383 }
21384
21385 DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_hthread *thr, duk_idx_t idx, duk_uint_t flag_mask) {
21386         duk_hobject *obj;
21387
21388         DUK_ASSERT_API_ENTRY(thr);
21389
21390         obj = duk_get_hobject(thr, idx);
21391         if (obj) {
21392                 return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
21393         }
21394         return 0;
21395 }
21396
21397 DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) {
21398         DUK_ASSERT(tv != NULL);
21399
21400 #if defined(DUK_USE_PACKED_TVAL)
21401         switch (DUK_TVAL_GET_TAG(tv)) {
21402         case DUK_TAG_UNUSED:
21403                 return DUK_TYPE_NONE;
21404         case DUK_TAG_UNDEFINED:
21405                 return DUK_TYPE_UNDEFINED;
21406         case DUK_TAG_NULL:
21407                 return DUK_TYPE_NULL;
21408         case DUK_TAG_BOOLEAN:
21409                 return DUK_TYPE_BOOLEAN;
21410         case DUK_TAG_STRING:
21411                 return DUK_TYPE_STRING;
21412         case DUK_TAG_OBJECT:
21413                 return DUK_TYPE_OBJECT;
21414         case DUK_TAG_BUFFER:
21415                 return DUK_TYPE_BUFFER;
21416         case DUK_TAG_POINTER:
21417                 return DUK_TYPE_POINTER;
21418         case DUK_TAG_LIGHTFUNC:
21419                 return DUK_TYPE_LIGHTFUNC;
21420 #if defined(DUK_USE_FASTINT)
21421         case DUK_TAG_FASTINT:
21422 #endif
21423         default:
21424                 /* Note: number has no explicit tag (in 8-byte representation) */
21425                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21426                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21427                 return DUK_TYPE_NUMBER;
21428         }
21429 #else  /* DUK_USE_PACKED_TVAL */
21430         DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
21431         DUK_ASSERT(sizeof(duk__type_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
21432         return (duk_int_t) duk__type_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
21433 #endif  /* DUK_USE_PACKED_TVAL */
21434 }
21435
21436 DUK_EXTERNAL duk_int_t duk_get_type(duk_hthread *thr, duk_idx_t idx) {
21437         duk_tval *tv;
21438
21439         DUK_ASSERT_API_ENTRY(thr);
21440
21441         tv = duk_get_tval_or_unused(thr, idx);
21442         DUK_ASSERT(tv != NULL);
21443
21444         return duk_get_type_tval(tv);
21445 }
21446
21447 #if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
21448 DUK_LOCAL const char * const duk__type_names[] = {
21449         "none",
21450         "undefined",
21451         "null",
21452         "boolean",
21453         "number",
21454         "string",
21455         "object",
21456         "buffer",
21457         "pointer",
21458         "lightfunc"
21459 };
21460
21461 DUK_INTERNAL const char *duk_get_type_name(duk_hthread *thr, duk_idx_t idx) {
21462         duk_int_t type_tag;
21463
21464         DUK_ASSERT_API_ENTRY(thr);
21465
21466         type_tag = duk_get_type(thr, idx);
21467         DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
21468         DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
21469
21470         return duk__type_names[type_tag];
21471 }
21472 #endif  /* DUK_USE_VERBOSE_ERRORS && DUK_USE_PARANOID_ERRORS */
21473
21474 DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_hthread *thr, duk_idx_t idx) {
21475         duk_tval *tv;
21476         duk_hobject *obj;
21477
21478         DUK_ASSERT_API_ENTRY(thr);
21479
21480         tv = duk_get_tval_or_unused(thr, idx);
21481         DUK_ASSERT(tv != NULL);
21482
21483         switch (DUK_TVAL_GET_TAG(tv)) {
21484         case DUK_TAG_OBJECT:
21485                 obj = DUK_TVAL_GET_OBJECT(tv);
21486                 DUK_ASSERT(obj != NULL);
21487                 return DUK_HOBJECT_GET_CLASS_NUMBER(obj);
21488         case DUK_TAG_BUFFER:
21489                 /* Buffers behave like Uint8Array objects. */
21490                 return DUK_HOBJECT_CLASS_UINT8ARRAY;
21491         case DUK_TAG_LIGHTFUNC:
21492                 /* Lightfuncs behave like Function objects. */
21493                 return DUK_HOBJECT_CLASS_FUNCTION;
21494         default:
21495                 /* Primitive or UNUSED, no class number. */
21496                 return DUK_HOBJECT_CLASS_NONE;
21497         }
21498 }
21499
21500 DUK_EXTERNAL duk_bool_t duk_check_type(duk_hthread *thr, duk_idx_t idx, duk_int_t type) {
21501         DUK_ASSERT_API_ENTRY(thr);
21502
21503         return (duk_get_type(thr, idx) == type) ? 1 : 0;
21504 }
21505
21506 DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) {
21507         DUK_ASSERT(tv != NULL);
21508
21509 #if defined(DUK_USE_PACKED_TVAL)
21510         switch (DUK_TVAL_GET_TAG(tv)) {
21511         case DUK_TAG_UNUSED:
21512                 return DUK_TYPE_MASK_NONE;
21513         case DUK_TAG_UNDEFINED:
21514                 return DUK_TYPE_MASK_UNDEFINED;
21515         case DUK_TAG_NULL:
21516                 return DUK_TYPE_MASK_NULL;
21517         case DUK_TAG_BOOLEAN:
21518                 return DUK_TYPE_MASK_BOOLEAN;
21519         case DUK_TAG_STRING:
21520                 return DUK_TYPE_MASK_STRING;
21521         case DUK_TAG_OBJECT:
21522                 return DUK_TYPE_MASK_OBJECT;
21523         case DUK_TAG_BUFFER:
21524                 return DUK_TYPE_MASK_BUFFER;
21525         case DUK_TAG_POINTER:
21526                 return DUK_TYPE_MASK_POINTER;
21527         case DUK_TAG_LIGHTFUNC:
21528                 return DUK_TYPE_MASK_LIGHTFUNC;
21529 #if defined(DUK_USE_FASTINT)
21530         case DUK_TAG_FASTINT:
21531 #endif
21532         default:
21533                 /* Note: number has no explicit tag (in 8-byte representation) */
21534                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
21535                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
21536                 return DUK_TYPE_MASK_NUMBER;
21537         }
21538 #else  /* DUK_USE_PACKED_TVAL */
21539         DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
21540         DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
21541         return duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
21542 #endif  /* DUK_USE_PACKED_TVAL */
21543 }
21544
21545 DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_hthread *thr, duk_idx_t idx) {
21546         duk_tval *tv;
21547
21548         DUK_ASSERT_API_ENTRY(thr);
21549
21550         tv = duk_get_tval_or_unused(thr, idx);
21551         DUK_ASSERT(tv != NULL);
21552
21553         return duk_get_type_mask_tval(tv);
21554 }
21555
21556 DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_hthread *thr, duk_idx_t idx, duk_uint_t mask) {
21557         DUK_ASSERT_API_ENTRY(thr);
21558
21559         if (DUK_LIKELY((duk_get_type_mask(thr, idx) & mask) != 0U)) {
21560                 return 1;
21561         }
21562         if (mask & DUK_TYPE_MASK_THROW) {
21563                 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
21564                 DUK_WO_NORETURN(return 0;);
21565         }
21566         return 0;
21567 }
21568
21569 DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_hthread *thr, duk_idx_t idx) {
21570         DUK_ASSERT_API_ENTRY(thr);
21571         return duk__tag_check(thr, idx, DUK_TAG_UNDEFINED);
21572 }
21573
21574 DUK_EXTERNAL duk_bool_t duk_is_null(duk_hthread *thr, duk_idx_t idx) {
21575         DUK_ASSERT_API_ENTRY(thr);
21576         return duk__tag_check(thr, idx, DUK_TAG_NULL);
21577 }
21578
21579 DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_hthread *thr, duk_idx_t idx) {
21580         DUK_ASSERT_API_ENTRY(thr);
21581         return duk__tag_check(thr, idx, DUK_TAG_BOOLEAN);
21582 }
21583
21584 DUK_EXTERNAL duk_bool_t duk_is_number(duk_hthread *thr, duk_idx_t idx) {
21585         duk_tval *tv;
21586
21587         DUK_ASSERT_API_ENTRY(thr);
21588
21589         /*
21590          *  Number is special because it doesn't have a specific
21591          *  tag in the 8-byte representation.
21592          */
21593
21594         /* XXX: shorter version for unpacked representation? */
21595
21596         tv = duk_get_tval_or_unused(thr, idx);
21597         DUK_ASSERT(tv != NULL);
21598         return DUK_TVAL_IS_NUMBER(tv);
21599 }
21600
21601 DUK_EXTERNAL duk_bool_t duk_is_nan(duk_hthread *thr, duk_idx_t idx) {
21602         /* XXX: This will now return false for non-numbers, even though they would
21603          * coerce to NaN (as a general rule).  In particular, duk_get_number()
21604          * returns a NaN for non-numbers, so should this function also return
21605          * true for non-numbers?
21606          */
21607
21608         duk_tval *tv;
21609
21610         DUK_ASSERT_API_ENTRY(thr);
21611
21612         tv = duk_get_tval_or_unused(thr, idx);
21613         DUK_ASSERT(tv != NULL);
21614
21615         /* XXX: for packed duk_tval an explicit "is number" check is unnecessary */
21616         if (!DUK_TVAL_IS_NUMBER(tv)) {
21617                 return 0;
21618         }
21619         return (duk_bool_t) DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
21620 }
21621
21622 DUK_EXTERNAL duk_bool_t duk_is_string(duk_hthread *thr, duk_idx_t idx) {
21623         DUK_ASSERT_API_ENTRY(thr);
21624         return duk__tag_check(thr, idx, DUK_TAG_STRING);
21625 }
21626
21627 DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_hthread *thr, duk_idx_t idx) {
21628         DUK_ASSERT_API_ENTRY(thr);
21629         return duk_get_hstring_notsymbol(thr, idx) != NULL;
21630 }
21631
21632 DUK_EXTERNAL duk_bool_t duk_is_object(duk_hthread *thr, duk_idx_t idx) {
21633         DUK_ASSERT_API_ENTRY(thr);
21634         return duk__tag_check(thr, idx, DUK_TAG_OBJECT);
21635 }
21636
21637 DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_hthread *thr, duk_idx_t idx) {
21638         DUK_ASSERT_API_ENTRY(thr);
21639         return duk__tag_check(thr, idx, DUK_TAG_BUFFER);
21640 }
21641
21642 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
21643 DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
21644         duk_tval *tv;
21645
21646         DUK_ASSERT_API_ENTRY(thr);
21647
21648         tv = duk_get_tval_or_unused(thr, idx);
21649         DUK_ASSERT(tv != NULL);
21650         if (DUK_TVAL_IS_BUFFER(tv)) {
21651                 return 1;
21652         } else if (DUK_TVAL_IS_OBJECT(tv)) {
21653                 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
21654                 DUK_ASSERT(h != NULL);
21655                 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
21656                         return 1;
21657                 }
21658         }
21659         return 0;
21660 }
21661 #else  /* DUK_USE_BUFFEROBJECT_SUPPORT */
21662 DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_hthread *thr, duk_idx_t idx) {
21663         DUK_ASSERT_API_ENTRY(thr);
21664
21665         return duk_is_buffer(thr, idx);
21666 }
21667
21668 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
21669
21670 DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_hthread *thr, duk_idx_t idx) {
21671         DUK_ASSERT_API_ENTRY(thr);
21672         return duk__tag_check(thr, idx, DUK_TAG_POINTER);
21673 }
21674
21675 DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_hthread *thr, duk_idx_t idx) {
21676         DUK_ASSERT_API_ENTRY(thr);
21677         return duk__tag_check(thr, idx, DUK_TAG_LIGHTFUNC);
21678 }
21679
21680 DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_hthread *thr, duk_idx_t idx) {
21681         duk_hstring *h;
21682
21683         DUK_ASSERT_API_ENTRY(thr);
21684         h = duk_get_hstring(thr, idx);
21685         /* Use DUK_LIKELY() here because caller may be more likely to type
21686          * check an expected symbol than not.
21687          */
21688         if (DUK_LIKELY(h != NULL && DUK_HSTRING_HAS_SYMBOL(h))) {
21689                 return 1;
21690         }
21691         return 0;
21692 }
21693
21694 DUK_EXTERNAL duk_bool_t duk_is_array(duk_hthread *thr, duk_idx_t idx) {
21695         duk_hobject *obj;
21696
21697         DUK_ASSERT_API_ENTRY(thr);
21698
21699         obj = duk_get_hobject(thr, idx);
21700         if (obj) {
21701                 return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
21702         }
21703         return 0;
21704 }
21705
21706 DUK_EXTERNAL duk_bool_t duk_is_function(duk_hthread *thr, duk_idx_t idx) {
21707         duk_tval *tv;
21708
21709         DUK_ASSERT_API_ENTRY(thr);
21710
21711         tv = duk_get_tval_or_unused(thr, idx);
21712         if (DUK_TVAL_IS_OBJECT(tv)) {
21713                 duk_hobject *h;
21714                 h = DUK_TVAL_GET_OBJECT(tv);
21715                 DUK_ASSERT(h != NULL);
21716                 return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
21717         }
21718         if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
21719                 return 1;
21720         }
21721         return 0;
21722 }
21723
21724 DUK_INTERNAL duk_bool_t duk_is_callable_tval(duk_hthread *thr, duk_tval *tv) {
21725         DUK_ASSERT_API_ENTRY(thr);
21726
21727         DUK_UNREF(thr);
21728
21729         if (DUK_TVAL_IS_OBJECT(tv)) {
21730                 duk_hobject *h;
21731                 h = DUK_TVAL_GET_OBJECT(tv);
21732                 DUK_ASSERT(h != NULL);
21733                 return DUK_HOBJECT_HAS_CALLABLE(h) ? 1 : 0;
21734         }
21735         if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
21736                 return 1;
21737         }
21738         return 0;
21739 }
21740
21741 DUK_EXTERNAL duk_bool_t duk_is_constructable(duk_hthread *thr, duk_idx_t idx) {
21742         duk_tval *tv;
21743
21744         DUK_ASSERT_API_ENTRY(thr);
21745
21746         tv = duk_get_tval_or_unused(thr, idx);
21747         if (DUK_TVAL_IS_OBJECT(tv)) {
21748                 duk_hobject *h;
21749                 h = DUK_TVAL_GET_OBJECT(tv);
21750                 DUK_ASSERT(h != NULL);
21751                 return DUK_HOBJECT_HAS_CONSTRUCTABLE(h) ? 1 : 0;
21752         }
21753         if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
21754                 return 1;
21755         }
21756         return 0;
21757 }
21758
21759 DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_hthread *thr, duk_idx_t idx) {
21760         DUK_ASSERT_API_ENTRY(thr);
21761         return duk__obj_flag_any_default_false(thr,
21762                                                idx,
21763                                                DUK_HOBJECT_FLAG_NATFUNC);
21764 }
21765
21766 DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_hthread *thr, duk_idx_t idx) {
21767         DUK_ASSERT_API_ENTRY(thr);
21768         return duk__obj_flag_any_default_false(thr,
21769                                                idx,
21770                                                DUK_HOBJECT_FLAG_COMPFUNC);
21771 }
21772
21773 DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_hthread *thr, duk_idx_t idx) {
21774         DUK_ASSERT_API_ENTRY(thr);
21775         return duk__obj_flag_any_default_false(thr,
21776                                                idx,
21777                                                DUK_HOBJECT_FLAG_BOUNDFUNC);
21778 }
21779
21780 DUK_EXTERNAL duk_bool_t duk_is_thread(duk_hthread *thr, duk_idx_t idx) {
21781         duk_hobject *obj;
21782
21783         DUK_ASSERT_API_ENTRY(thr);
21784
21785         obj = duk_get_hobject(thr, idx);
21786         if (obj) {
21787                 return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_THREAD ? 1 : 0);
21788         }
21789         return 0;
21790 }
21791
21792 DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_hthread *thr, duk_idx_t idx) {
21793         duk_tval *tv;
21794
21795         DUK_ASSERT_API_ENTRY(thr);
21796
21797         tv = duk_get_tval_or_unused(thr, idx);
21798         DUK_ASSERT(tv != NULL);
21799         if (DUK_TVAL_IS_BUFFER(tv)) {
21800                 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
21801                 DUK_ASSERT(h != NULL);
21802                 return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
21803         }
21804         return 0;
21805 }
21806
21807 DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_hthread *thr, duk_idx_t idx) {
21808         duk_tval *tv;
21809
21810         DUK_ASSERT_API_ENTRY(thr);
21811
21812         tv = duk_get_tval_or_unused(thr, idx);
21813         DUK_ASSERT(tv != NULL);
21814         if (DUK_TVAL_IS_BUFFER(tv)) {
21815                 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
21816                 DUK_ASSERT(h != NULL);
21817                 return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
21818         }
21819         return 0;
21820 }
21821
21822 DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_hthread *thr, duk_idx_t idx) {
21823         duk_tval *tv;
21824
21825         DUK_ASSERT_API_ENTRY(thr);
21826
21827         tv = duk_get_tval_or_unused(thr, idx);
21828         DUK_ASSERT(tv != NULL);
21829         if (DUK_TVAL_IS_BUFFER(tv)) {
21830                 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
21831                 DUK_ASSERT(h != NULL);
21832                 return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
21833         }
21834         return 0;
21835 }
21836
21837 DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_hthread *thr, duk_idx_t idx) {
21838         duk_hobject *h;
21839         duk_uint_t sanity;
21840
21841         DUK_ASSERT_API_ENTRY(thr);
21842
21843         h = duk_get_hobject(thr, idx);
21844
21845         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
21846         do {
21847                 if (!h) {
21848                         return DUK_ERR_NONE;
21849                 }
21850
21851                 /* XXX: something more convenient? */
21852
21853                 if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
21854                         return DUK_ERR_EVAL_ERROR;
21855                 }
21856                 if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) {
21857                         return DUK_ERR_RANGE_ERROR;
21858                 }
21859                 if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) {
21860                         return DUK_ERR_REFERENCE_ERROR;
21861                 }
21862                 if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) {
21863                         return DUK_ERR_SYNTAX_ERROR;
21864                 }
21865                 if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) {
21866                         return DUK_ERR_TYPE_ERROR;
21867                 }
21868                 if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) {
21869                         return DUK_ERR_URI_ERROR;
21870                 }
21871                 if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) {
21872                         return DUK_ERR_ERROR;
21873                 }
21874
21875                 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
21876         } while (--sanity > 0);
21877
21878         return DUK_ERR_NONE;
21879 }
21880
21881 /*
21882  *  Pushers
21883  */
21884
21885 DUK_INTERNAL void duk_push_tval(duk_hthread *thr, duk_tval *tv) {
21886         duk_tval *tv_slot;
21887
21888         DUK_ASSERT_API_ENTRY(thr);
21889         DUK_ASSERT(tv != NULL);
21890
21891         DUK__CHECK_SPACE();
21892         tv_slot = thr->valstack_top++;
21893         DUK_TVAL_SET_TVAL(tv_slot, tv);
21894         DUK_TVAL_INCREF(thr, tv);  /* no side effects */
21895 }
21896
21897 DUK_EXTERNAL void duk_push_undefined(duk_hthread *thr) {
21898         DUK_ASSERT_API_ENTRY(thr);
21899
21900         DUK__CHECK_SPACE();
21901
21902         /* Because value stack init policy is 'undefined above top',
21903          * we don't need to write, just assert.
21904          */
21905         thr->valstack_top++;
21906         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
21907 }
21908
21909 DUK_EXTERNAL void duk_push_null(duk_hthread *thr) {
21910         duk_tval *tv_slot;
21911
21912         DUK_ASSERT_API_ENTRY(thr);
21913         DUK__CHECK_SPACE();
21914         tv_slot = thr->valstack_top++;
21915         DUK_TVAL_SET_NULL(tv_slot);
21916 }
21917
21918 DUK_EXTERNAL void duk_push_boolean(duk_hthread *thr, duk_bool_t val) {
21919         duk_tval *tv_slot;
21920         duk_small_int_t b;
21921
21922         DUK_ASSERT_API_ENTRY(thr);
21923         DUK__CHECK_SPACE();
21924         b = (val ? 1 : 0);  /* ensure value is 1 or 0 (not other non-zero) */
21925         tv_slot = thr->valstack_top++;
21926         DUK_TVAL_SET_BOOLEAN(tv_slot, b);
21927 }
21928
21929 DUK_EXTERNAL void duk_push_true(duk_hthread *thr) {
21930         duk_tval *tv_slot;
21931
21932         DUK_ASSERT_API_ENTRY(thr);
21933         DUK__CHECK_SPACE();
21934         tv_slot = thr->valstack_top++;
21935         DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
21936 }
21937
21938 DUK_EXTERNAL void duk_push_false(duk_hthread *thr) {
21939         duk_tval *tv_slot;
21940
21941         DUK_ASSERT_API_ENTRY(thr);
21942         DUK__CHECK_SPACE();
21943         tv_slot = thr->valstack_top++;
21944         DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
21945 }
21946
21947 /* normalize NaN which may not match our canonical internal NaN */
21948 DUK_EXTERNAL void duk_push_number(duk_hthread *thr, duk_double_t val) {
21949         duk_tval *tv_slot;
21950         duk_double_union du;
21951
21952         DUK_ASSERT_API_ENTRY(thr);
21953         DUK__CHECK_SPACE();
21954         du.d = val;
21955         DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
21956         tv_slot = thr->valstack_top++;
21957         DUK_TVAL_SET_NUMBER(tv_slot, du.d);
21958 }
21959
21960 DUK_EXTERNAL void duk_push_int(duk_hthread *thr, duk_int_t val) {
21961 #if defined(DUK_USE_FASTINT)
21962         duk_tval *tv_slot;
21963
21964         DUK_ASSERT_API_ENTRY(thr);
21965         DUK__CHECK_SPACE();
21966         tv_slot = thr->valstack_top++;
21967 #if DUK_INT_MAX <= 0x7fffffffL
21968         DUK_TVAL_SET_I32(tv_slot, (duk_int32_t) val);
21969 #else
21970         if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) {
21971                 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
21972         } else {
21973                 duk_double_t = (duk_double_t) val;
21974                 DUK_TVAL_SET_NUMBER(tv_slot, d);
21975         }
21976 #endif
21977 #else  /* DUK_USE_FASTINT */
21978         duk_tval *tv_slot;
21979         duk_double_t d;
21980
21981         DUK_ASSERT_API_ENTRY(thr);
21982         DUK__CHECK_SPACE();
21983         d = (duk_double_t) val;
21984         tv_slot = thr->valstack_top++;
21985         DUK_TVAL_SET_NUMBER(tv_slot, d);
21986 #endif  /* DUK_USE_FASTINT */
21987 }
21988
21989 DUK_EXTERNAL void duk_push_uint(duk_hthread *thr, duk_uint_t val) {
21990 #if defined(DUK_USE_FASTINT)
21991         duk_tval *tv_slot;
21992
21993         DUK_ASSERT_API_ENTRY(thr);
21994         DUK__CHECK_SPACE();
21995         tv_slot = thr->valstack_top++;
21996 #if DUK_UINT_MAX <= 0xffffffffUL
21997         DUK_TVAL_SET_U32(tv_slot, (duk_uint32_t) val);
21998 #else
21999         if (val <= DUK_FASTINT_MAX) {  /* val is unsigned so >= 0 */
22000                 /* XXX: take advantage of val being unsigned, no need to mask */
22001                 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
22002         } else {
22003                 duk_double_t = (duk_double_t) val;
22004                 DUK_TVAL_SET_NUMBER(tv_slot, d);
22005         }
22006 #endif
22007 #else  /* DUK_USE_FASTINT */
22008         duk_tval *tv_slot;
22009         duk_double_t d;
22010
22011         DUK_ASSERT_API_ENTRY(thr);
22012         DUK__CHECK_SPACE();
22013         d = (duk_double_t) val;
22014         tv_slot = thr->valstack_top++;
22015         DUK_TVAL_SET_NUMBER(tv_slot, d);
22016 #endif  /* DUK_USE_FASTINT */
22017 }
22018
22019 DUK_EXTERNAL void duk_push_nan(duk_hthread *thr) {
22020         duk_tval *tv_slot;
22021         duk_double_union du;
22022
22023         DUK_ASSERT_API_ENTRY(thr);
22024         DUK__CHECK_SPACE();
22025         DUK_DBLUNION_SET_NAN(&du);
22026         DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
22027         tv_slot = thr->valstack_top++;
22028         DUK_TVAL_SET_NUMBER(tv_slot, du.d);
22029 }
22030
22031 DUK_EXTERNAL const char *duk_push_lstring(duk_hthread *thr, const char *str, duk_size_t len) {
22032         duk_hstring *h;
22033         duk_tval *tv_slot;
22034
22035         DUK_ASSERT_API_ENTRY(thr);
22036
22037         /* Check stack before interning (avoid hanging temp). */
22038         DUK__CHECK_SPACE();
22039
22040         /* NULL with zero length represents an empty string; NULL with higher
22041          * length is also now treated like an empty string although it is
22042          * a bit dubious.  This is unlike duk_push_string() which pushes a
22043          * 'null' if the input string is a NULL.
22044          */
22045         if (DUK_UNLIKELY(str == NULL)) {
22046                 len = 0U;
22047         }
22048
22049         /* Check for maximum string length. */
22050         if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) {
22051                 DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
22052                 DUK_WO_NORETURN(return NULL;);
22053         }
22054
22055         h = duk_heap_strtable_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
22056         DUK_ASSERT(h != NULL);
22057
22058         tv_slot = thr->valstack_top++;
22059         DUK_TVAL_SET_STRING(tv_slot, h);
22060         DUK_HSTRING_INCREF(thr, h);  /* no side effects */
22061
22062         return (const char *) DUK_HSTRING_GET_DATA(h);
22063 }
22064
22065 DUK_EXTERNAL const char *duk_push_string(duk_hthread *thr, const char *str) {
22066         DUK_ASSERT_API_ENTRY(thr);
22067
22068         if (str) {
22069                 return duk_push_lstring(thr, str, DUK_STRLEN(str));
22070         } else {
22071                 duk_push_null(thr);
22072                 return NULL;
22073         }
22074 }
22075
22076 #if !defined(DUK_USE_PREFER_SIZE)
22077 #if defined(DUK_USE_LITCACHE_SIZE)
22078 DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) {
22079         duk_hstring *h;
22080         duk_tval *tv_slot;
22081
22082         DUK_ASSERT_API_ENTRY(thr);
22083         DUK_ASSERT(str != NULL);
22084         DUK_ASSERT(str[len] == (char) 0);
22085
22086         /* Check for maximum string length. */
22087         if (DUK_UNLIKELY(len > DUK_HSTRING_MAX_BYTELEN)) {
22088                 DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
22089                 DUK_WO_NORETURN(return NULL;);
22090         }
22091
22092         h = duk_heap_strtable_intern_literal_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
22093         DUK_ASSERT(h != NULL);
22094
22095         tv_slot = thr->valstack_top++;
22096         DUK_TVAL_SET_STRING(tv_slot, h);
22097         DUK_HSTRING_INCREF(thr, h);  /* no side effects */
22098
22099         return (const char *) DUK_HSTRING_GET_DATA(h);
22100 }
22101 #else  /* DUK_USE_LITCACHE_SIZE */
22102 DUK_EXTERNAL const char *duk_push_literal_raw(duk_hthread *thr, const char *str, duk_size_t len) {
22103         DUK_ASSERT_API_ENTRY(thr);
22104         DUK_ASSERT(str != NULL);
22105         DUK_ASSERT(str[len] == (char) 0);
22106
22107         return duk_push_lstring(thr, str, len);
22108 }
22109 #endif  /* DUK_USE_LITCACHE_SIZE */
22110 #endif  /* !DUK_USE_PREFER_SIZE */
22111
22112 DUK_EXTERNAL void duk_push_pointer(duk_hthread *thr, void *val) {
22113         duk_tval *tv_slot;
22114
22115         DUK_ASSERT_API_ENTRY(thr);
22116         DUK__CHECK_SPACE();
22117         tv_slot = thr->valstack_top++;
22118         DUK_TVAL_SET_POINTER(tv_slot, val);
22119 }
22120
22121 DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_hthread *thr, duk_uint_t i) {
22122         duk_hstring *h_tmp;
22123
22124         DUK_ASSERT_API_ENTRY(thr);
22125
22126         /* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */
22127         duk_push_uint(thr, (duk_uint_t) i);
22128         h_tmp = duk_to_hstring_m1(thr);
22129         DUK_ASSERT(h_tmp != NULL);
22130         return h_tmp;
22131 }
22132
22133 DUK_LOCAL void duk__push_this_helper(duk_hthread *thr, duk_small_uint_t check_object_coercible) {
22134         duk_tval *tv_slot;
22135
22136         DUK__CHECK_SPACE();
22137
22138         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));  /* because of valstack init policy */
22139         tv_slot = thr->valstack_top++;
22140
22141         if (DUK_UNLIKELY(thr->callstack_curr == NULL)) {
22142                 if (check_object_coercible) {
22143                         goto type_error;
22144                 }
22145                 /* 'undefined' already on stack top */
22146         } else {
22147                 duk_tval *tv;
22148
22149                 /* 'this' binding is just before current activation's bottom */
22150                 DUK_ASSERT(thr->valstack_bottom > thr->valstack);
22151                 tv = thr->valstack_bottom - 1;
22152                 if (check_object_coercible &&
22153                     (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) {
22154                         /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */
22155                         goto type_error;
22156                 }
22157
22158                 DUK_TVAL_SET_TVAL(tv_slot, tv);
22159                 DUK_TVAL_INCREF(thr, tv);
22160         }
22161         return;
22162
22163  type_error:
22164         DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
22165         DUK_WO_NORETURN(return;);
22166 }
22167
22168 DUK_EXTERNAL void duk_push_this(duk_hthread *thr) {
22169         DUK_ASSERT_API_ENTRY(thr);
22170
22171         duk__push_this_helper(thr, 0 /*check_object_coercible*/);
22172 }
22173
22174 DUK_INTERNAL void duk_push_this_check_object_coercible(duk_hthread *thr) {
22175         DUK_ASSERT_API_ENTRY(thr);
22176
22177         duk__push_this_helper(thr, 1 /*check_object_coercible*/);
22178 }
22179
22180 DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_hthread *thr) {
22181         duk_hobject *h;
22182
22183         DUK_ASSERT_API_ENTRY(thr);
22184
22185         duk__push_this_helper(thr, 1 /*check_object_coercible*/);
22186         h = duk_to_hobject(thr, -1);
22187         DUK_ASSERT(h != NULL);
22188         return h;
22189 }
22190
22191 DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_hthread *thr) {
22192         DUK_ASSERT_API_ENTRY(thr);
22193
22194         duk__push_this_helper(thr, 1 /*check_object_coercible*/);
22195         return duk_to_hstring_m1(thr);  /* This will reject all Symbol values; accepts Symbol objects. */
22196 }
22197
22198 DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_hthread *thr) {
22199         DUK_ASSERT_API_ENTRY(thr);
22200
22201         DUK_ASSERT(thr->callstack_top > 0);  /* caller required to know */
22202         DUK_ASSERT(thr->callstack_curr != NULL);  /* caller required to know */
22203         DUK_ASSERT(thr->valstack_bottom > thr->valstack);  /* consequence of above */
22204         DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack);  /* 'this' binding exists */
22205
22206         return thr->valstack_bottom - 1;
22207 }
22208
22209 DUK_EXTERNAL void duk_push_new_target(duk_hthread *thr) {
22210         duk_activation *act;
22211
22212         DUK_ASSERT_API_ENTRY(thr);
22213
22214         /* https://www.ecma-international.org/ecma-262/6.0/#sec-meta-properties-runtime-semantics-evaluation
22215          * https://www.ecma-international.org/ecma-262/6.0/#sec-getnewtarget
22216          *
22217          * No newTarget support now, so as a first approximation
22218          * use the resolved (non-bound) target function.
22219          *
22220          * Check CONSTRUCT flag from current function, or if running
22221          * direct eval, from a non-direct-eval parent (with possibly
22222          * more than one nested direct eval).  An alternative to this
22223          * would be to store [[NewTarget]] as a hidden symbol of the
22224          * lexical scope, and then just look up that variable.
22225          *
22226          * Calls from the application will either be for an empty
22227          * call stack, or a Duktape/C function as the top activation.
22228          */
22229
22230         act = thr->callstack_curr;
22231         for (;;) {
22232                 if (act == NULL) {
22233                         break;
22234                 }
22235
22236                 if (act->flags & DUK_ACT_FLAG_CONSTRUCT) {
22237                         duk_push_tval(thr, &act->tv_func);
22238                         return;
22239                 } else if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
22240                         act = act->parent;
22241                 } else {
22242                         break;
22243                 }
22244         }
22245
22246         duk_push_undefined(thr);
22247 }
22248
22249 DUK_EXTERNAL void duk_push_current_function(duk_hthread *thr) {
22250         duk_activation *act;
22251
22252         DUK_ASSERT_API_ENTRY(thr);
22253
22254         act = thr->callstack_curr;
22255         if (act != NULL) {
22256                 duk_push_tval(thr, &act->tv_func);
22257         } else {
22258                 duk_push_undefined(thr);
22259         }
22260 }
22261
22262 DUK_EXTERNAL void duk_push_current_thread(duk_hthread *thr) {
22263         DUK_ASSERT_API_ENTRY(thr);
22264
22265         if (thr->heap->curr_thread) {
22266                 duk_push_hobject(thr, (duk_hobject *) thr->heap->curr_thread);
22267         } else {
22268                 duk_push_undefined(thr);
22269         }
22270 }
22271
22272 DUK_EXTERNAL void duk_push_global_object(duk_hthread *thr) {
22273         DUK_ASSERT_API_ENTRY(thr);
22274
22275         duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
22276 }
22277
22278 /* XXX: size optimize */
22279 DUK_LOCAL void duk__push_stash(duk_hthread *thr) {
22280         if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE)) {
22281                 DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
22282                 duk_pop_unsafe(thr);
22283                 duk_push_bare_object(thr);
22284                 duk_dup_top(thr);
22285                 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C);  /* [ ... parent stash stash ] -> [ ... parent stash ] */
22286         }
22287         duk_remove_m2(thr);
22288 }
22289
22290 DUK_EXTERNAL void duk_push_heap_stash(duk_hthread *thr) {
22291         duk_heap *heap;
22292         DUK_ASSERT_API_ENTRY(thr);
22293         heap = thr->heap;
22294         DUK_ASSERT(heap->heap_object != NULL);
22295         duk_push_hobject(thr, heap->heap_object);
22296         duk__push_stash(thr);
22297 }
22298
22299 DUK_EXTERNAL void duk_push_global_stash(duk_hthread *thr) {
22300         DUK_ASSERT_API_ENTRY(thr);
22301         duk_push_global_object(thr);
22302         duk__push_stash(thr);
22303 }
22304
22305 DUK_EXTERNAL void duk_push_thread_stash(duk_hthread *thr, duk_hthread *target_thr) {
22306         DUK_ASSERT_API_ENTRY(thr);
22307         if (DUK_UNLIKELY(target_thr == NULL)) {
22308                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
22309                 DUK_WO_NORETURN(return;);
22310         }
22311         duk_push_hobject(thr, (duk_hobject *) target_thr);
22312         duk__push_stash(thr);
22313 }
22314
22315 /* XXX: duk_ssize_t would be useful here */
22316 DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_hthread *thr, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
22317         duk_int_t len;
22318
22319         DUK_ASSERT_CTX_VALID(thr);
22320         DUK_UNREF(thr);
22321
22322         /* NUL terminator handling doesn't matter here */
22323         len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
22324         if (len < (duk_int_t) sz) {
22325                 /* Return value of 'sz' or more indicates output was (potentially)
22326                  * truncated.
22327                  */
22328                 return (duk_int_t) len;
22329         }
22330         return -1;
22331 }
22332
22333 DUK_EXTERNAL const char *duk_push_vsprintf(duk_hthread *thr, const char *fmt, va_list ap) {
22334         duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
22335         duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
22336         duk_bool_t pushed_buf = 0;
22337         void *buf;
22338         duk_int_t len;  /* XXX: duk_ssize_t */
22339         const char *res;
22340
22341         DUK_ASSERT_API_ENTRY(thr);
22342
22343         /* special handling of fmt==NULL */
22344         if (!fmt) {
22345                 duk_hstring *h_str;
22346                 duk_push_hstring_empty(thr);
22347                 h_str = duk_known_hstring(thr, -1);
22348                 return (const char *) DUK_HSTRING_GET_DATA(h_str);
22349         }
22350
22351         /* initial estimate based on format string */
22352         sz = DUK_STRLEN(fmt) + 16;  /* format plus something to avoid just missing */
22353         if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) {
22354                 sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
22355         }
22356         DUK_ASSERT(sz > 0);
22357
22358         /* Try to make do with a stack buffer to avoid allocating a temporary buffer.
22359          * This works 99% of the time which is quite nice.
22360          */
22361         for (;;) {
22362                 va_list ap_copy;  /* copied so that 'ap' can be reused */
22363
22364                 if (sz <= sizeof(stack_buf)) {
22365                         buf = stack_buf;
22366                 } else if (!pushed_buf) {
22367                         pushed_buf = 1;
22368                         buf = duk_push_dynamic_buffer(thr, sz);
22369                 } else {
22370                         buf = duk_resize_buffer(thr, -1, sz);
22371                 }
22372                 DUK_ASSERT(buf != NULL);
22373
22374                 DUK_VA_COPY(ap_copy, ap);
22375                 len = duk__try_push_vsprintf(thr, buf, sz, fmt, ap_copy);
22376                 va_end(ap_copy);
22377                 if (len >= 0) {
22378                         break;
22379                 }
22380
22381                 /* failed, resize and try again */
22382                 sz = sz * 2;
22383                 if (DUK_UNLIKELY(sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT)) {
22384                         DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
22385                         DUK_WO_NORETURN(return NULL;);
22386                 }
22387         }
22388
22389         /* Cannot use duk_buffer_to_string() on the buffer because it is
22390          * usually larger than 'len'; 'buf' is also usually a stack buffer.
22391          */
22392         res = duk_push_lstring(thr, (const char *) buf, (duk_size_t) len);  /* [ buf? res ] */
22393         if (pushed_buf) {
22394                 duk_remove_m2(thr);
22395         }
22396         return res;
22397 }
22398
22399 DUK_EXTERNAL const char *duk_push_sprintf(duk_hthread *thr, const char *fmt, ...) {
22400         va_list ap;
22401         const char *ret;
22402
22403         DUK_ASSERT_API_ENTRY(thr);
22404
22405         /* allow fmt==NULL */
22406         va_start(ap, fmt);
22407         ret = duk_push_vsprintf(thr, fmt, ap);
22408         va_end(ap);
22409
22410         return ret;
22411 }
22412
22413 DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
22414         duk_tval *tv_slot;
22415         duk_hobject *h;
22416
22417         DUK_ASSERT_API_ENTRY(thr);
22418         DUK_ASSERT(prototype_bidx == -1 ||
22419                    (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
22420
22421         DUK__CHECK_SPACE();
22422
22423         h = duk_hobject_alloc(thr, hobject_flags_and_class);
22424         DUK_ASSERT(h != NULL);
22425
22426         DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags));
22427
22428         tv_slot = thr->valstack_top;
22429         DUK_TVAL_SET_OBJECT(tv_slot, h);
22430         DUK_HOBJECT_INCREF(thr, h);  /* no side effects */
22431         thr->valstack_top++;
22432
22433         /* object is now reachable */
22434
22435         if (prototype_bidx >= 0) {
22436                 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, thr->builtins[prototype_bidx]);
22437         } else {
22438                 DUK_ASSERT(prototype_bidx == -1);
22439                 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
22440         }
22441
22442         return h;
22443 }
22444
22445 DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
22446         duk_hobject *h;
22447
22448         DUK_ASSERT_API_ENTRY(thr);
22449
22450         h = duk_push_object_helper(thr, hobject_flags_and_class, -1);
22451         DUK_ASSERT(h != NULL);
22452         DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, h, proto);
22453         return h;
22454 }
22455
22456 DUK_EXTERNAL duk_idx_t duk_push_object(duk_hthread *thr) {
22457         DUK_ASSERT_API_ENTRY(thr);
22458
22459         (void) duk_push_object_helper(thr,
22460                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
22461                                       DUK_HOBJECT_FLAG_FASTREFS |
22462                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
22463                                       DUK_BIDX_OBJECT_PROTOTYPE);
22464         return duk_get_top_index_unsafe(thr);
22465 }
22466
22467 DUK_EXTERNAL duk_idx_t duk_push_array(duk_hthread *thr) {
22468         duk_uint_t flags;
22469         duk_harray *obj;
22470         duk_idx_t ret;
22471         duk_tval *tv_slot;
22472
22473         DUK_ASSERT_API_ENTRY(thr);
22474
22475         flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
22476                 DUK_HOBJECT_FLAG_FASTREFS |
22477                 DUK_HOBJECT_FLAG_ARRAY_PART |
22478                 DUK_HOBJECT_FLAG_EXOTIC_ARRAY |
22479                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY);
22480
22481         obj = duk_harray_alloc(thr, flags);
22482         DUK_ASSERT(obj != NULL);
22483
22484         DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]);
22485
22486         tv_slot = thr->valstack_top;
22487         DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
22488         DUK_HOBJECT_INCREF(thr, obj);  /* XXX: could preallocate with refcount = 1 */
22489         ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
22490         thr->valstack_top++;
22491
22492         DUK_ASSERT(obj->length == 0);  /* Array .length starts at zero. */
22493         return ret;
22494 }
22495
22496 DUK_INTERNAL duk_harray *duk_push_harray(duk_hthread *thr) {
22497         /* XXX: API call could do this directly, cast to void in API macro. */
22498         duk_harray *a;
22499
22500         DUK_ASSERT_API_ENTRY(thr);
22501
22502         (void) duk_push_array(thr);
22503         DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1));
22504         a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1);
22505         DUK_ASSERT(a != NULL);
22506         return a;
22507 }
22508
22509 /* Push a duk_harray with preallocated size (.length also set to match size).
22510  * Caller may then populate array part of the duk_harray directly.
22511  */
22512 DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_hthread *thr, duk_uint32_t size) {
22513         duk_harray *a;
22514
22515         DUK_ASSERT_API_ENTRY(thr);
22516
22517         a = duk_push_harray(thr);
22518
22519         duk_hobject_realloc_props(thr,
22520                                   (duk_hobject *) a,
22521                                   0,
22522                                   size,
22523                                   0,
22524                                   0);
22525         a->length = size;
22526         return a;
22527 }
22528
22529 DUK_INTERNAL duk_tval *duk_push_harray_with_size_outptr(duk_hthread *thr, duk_uint32_t size) {
22530         duk_harray *a;
22531
22532         DUK_ASSERT_API_ENTRY(thr);
22533
22534         a = duk_push_harray_with_size(thr, size);
22535         DUK_ASSERT(a != NULL);
22536         return DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
22537 }
22538
22539 DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_hthread *thr, duk_uint_t flags) {
22540         duk_hthread *obj;
22541         duk_idx_t ret;
22542         duk_tval *tv_slot;
22543
22544         DUK_ASSERT_API_ENTRY(thr);
22545
22546         DUK__CHECK_SPACE();
22547
22548         obj = duk_hthread_alloc(thr,
22549                                 DUK_HOBJECT_FLAG_EXTENSIBLE |
22550                                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
22551         DUK_ASSERT(obj != NULL);
22552         obj->state = DUK_HTHREAD_STATE_INACTIVE;
22553 #if defined(DUK_USE_ROM_STRINGS)
22554         /* Nothing to initialize, strs[] is in ROM. */
22555 #else
22556 #if defined(DUK_USE_HEAPPTR16)
22557         obj->strs16 = thr->strs16;
22558 #else
22559         obj->strs = thr->strs;
22560 #endif
22561 #endif
22562         DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
22563
22564         /* make the new thread reachable */
22565         tv_slot = thr->valstack_top;
22566         DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
22567         DUK_HTHREAD_INCREF(thr, obj);
22568         ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
22569         thr->valstack_top++;
22570
22571         /* important to do this *after* pushing, to make the thread reachable for gc */
22572         if (DUK_UNLIKELY(!duk_hthread_init_stacks(thr->heap, obj))) {
22573                 DUK_ERROR_ALLOC_FAILED(thr);
22574                 DUK_WO_NORETURN(return 0;);
22575         }
22576
22577         /* initialize built-ins - either by copying or creating new ones */
22578         if (flags & DUK_THREAD_NEW_GLOBAL_ENV) {
22579                 duk_hthread_create_builtin_objects(obj);
22580         } else {
22581                 duk_hthread_copy_builtin_objects(thr, obj);
22582         }
22583
22584         /* default prototype */
22585         DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
22586
22587         /* Initial stack size satisfies the stack slack constraints so there
22588          * is no need to require stack here.
22589          */
22590         DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
22591                    DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
22592
22593         return ret;
22594 }
22595
22596 DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_hthread *thr) {
22597         duk_hcompfunc *obj;
22598         duk_tval *tv_slot;
22599
22600         DUK_ASSERT_API_ENTRY(thr);
22601
22602         DUK__CHECK_SPACE();
22603
22604         /* Template functions are not strictly constructable (they don't
22605          * have a "prototype" property for instance), so leave the
22606          * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
22607          */
22608
22609         obj = duk_hcompfunc_alloc(thr,
22610                                   DUK_HOBJECT_FLAG_EXTENSIBLE |
22611                                   DUK_HOBJECT_FLAG_CALLABLE |
22612                                   DUK_HOBJECT_FLAG_COMPFUNC |
22613                                   DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
22614         if (DUK_UNLIKELY(obj == NULL)) {
22615                 DUK_ERROR_ALLOC_FAILED(thr);
22616                 DUK_WO_NORETURN(return NULL;);
22617         }
22618
22619         DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
22620
22621         tv_slot = thr->valstack_top;
22622         DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
22623         DUK_HOBJECT_INCREF(thr, obj);
22624         thr->valstack_top++;
22625
22626         /* default prototype */
22627         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
22628         DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
22629
22630         return obj;
22631 }
22632
22633 DUK_INTERNAL duk_hboundfunc *duk_push_hboundfunc(duk_hthread *thr) {
22634         duk_hboundfunc *obj;
22635         duk_tval *tv_slot;
22636
22637         DUK_ASSERT_API_ENTRY(thr);
22638
22639         DUK__CHECK_SPACE();
22640         obj = duk_hboundfunc_alloc(thr->heap,
22641                                    DUK_HOBJECT_FLAG_EXTENSIBLE |
22642                                    DUK_HOBJECT_FLAG_BOUNDFUNC |
22643                                    DUK_HOBJECT_FLAG_CONSTRUCTABLE |
22644                                    DUK_HOBJECT_FLAG_CALLABLE |
22645                                    DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
22646         if (!obj) {
22647                 DUK_ERROR_ALLOC_FAILED(thr);
22648                 DUK_WO_NORETURN(return NULL;);
22649         }
22650
22651         tv_slot = thr->valstack_top++;
22652         DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
22653         DUK_HOBJECT_INCREF(thr, obj);
22654
22655         /* Prototype is left as NULL because the caller always sets it (and
22656          * it depends on the target function).
22657          */
22658         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) obj) == NULL);
22659
22660         return obj;
22661 }
22662
22663 DUK_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) {
22664         duk_hnatfunc *obj;
22665         duk_idx_t ret;
22666         duk_tval *tv_slot;
22667         duk_int16_t func_nargs;
22668
22669         DUK_ASSERT_CTX_VALID(thr);
22670
22671         DUK__CHECK_SPACE();
22672
22673         if (DUK_UNLIKELY(func == NULL)) {
22674                 goto api_error;
22675         }
22676         if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) {
22677                 func_nargs = (duk_int16_t) nargs;
22678         } else if (nargs == DUK_VARARGS) {
22679                 func_nargs = DUK_HNATFUNC_NARGS_VARARGS;
22680         } else {
22681                 goto api_error;
22682         }
22683
22684         obj = duk_hnatfunc_alloc(thr, flags);
22685         DUK_ASSERT(obj != NULL);
22686
22687         obj->func = func;
22688         obj->nargs = func_nargs;
22689
22690         DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld",
22691                              (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs));
22692
22693         tv_slot = thr->valstack_top;
22694         DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
22695         DUK_HOBJECT_INCREF(thr, obj);
22696         ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
22697         thr->valstack_top++;
22698
22699         DUK_ASSERT_BIDX_VALID(proto_bidx);
22700         DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[proto_bidx]);
22701         return ret;
22702
22703  api_error:
22704         DUK_ERROR_TYPE_INVALID_ARGS(thr);
22705         DUK_WO_NORETURN(return 0;);
22706 }
22707
22708 DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
22709         duk_uint_t flags;
22710
22711         DUK_ASSERT_API_ENTRY(thr);
22712
22713         flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
22714                 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
22715                 DUK_HOBJECT_FLAG_CALLABLE |
22716                 DUK_HOBJECT_FLAG_FASTREFS |
22717                 DUK_HOBJECT_FLAG_NATFUNC |
22718                 DUK_HOBJECT_FLAG_NEWENV |
22719                 DUK_HOBJECT_FLAG_STRICT |
22720                 DUK_HOBJECT_FLAG_NOTAIL |
22721                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
22722
22723         /* Default prototype is a Duktape specific %NativeFunctionPrototype%
22724          * which provides .length and .name getters.
22725          */
22726         return duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE);
22727 }
22728
22729 DUK_INTERNAL void duk_push_c_function_builtin(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
22730         duk_uint_t flags;
22731
22732         DUK_ASSERT_API_ENTRY(thr);
22733
22734         flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
22735                 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
22736                 DUK_HOBJECT_FLAG_CALLABLE |
22737                 DUK_HOBJECT_FLAG_FASTREFS |
22738                 DUK_HOBJECT_FLAG_NATFUNC |
22739                 DUK_HOBJECT_FLAG_NEWENV |
22740                 DUK_HOBJECT_FLAG_STRICT |
22741                 DUK_HOBJECT_FLAG_NOTAIL |
22742                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
22743
22744         /* Must use Function.prototype for standard built-in functions. */
22745         (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
22746 }
22747
22748 DUK_INTERNAL void duk_push_c_function_builtin_noconstruct(duk_hthread *thr, duk_c_function func, duk_int_t nargs) {
22749         duk_uint_t flags;
22750
22751         DUK_ASSERT_API_ENTRY(thr);
22752
22753         flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
22754                 DUK_HOBJECT_FLAG_CALLABLE |
22755                 DUK_HOBJECT_FLAG_FASTREFS |
22756                 DUK_HOBJECT_FLAG_NATFUNC |
22757                 DUK_HOBJECT_FLAG_NEWENV |
22758                 DUK_HOBJECT_FLAG_STRICT |
22759                 DUK_HOBJECT_FLAG_NOTAIL |
22760                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
22761
22762         /* Must use Function.prototype for standard built-in functions. */
22763         (void) duk__push_c_function_raw(thr, func, nargs, flags, DUK_BIDX_FUNCTION_PROTOTYPE);
22764 }
22765
22766 DUK_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) {
22767         duk_small_uint_t lf_flags;
22768         duk_tval *tv_slot;
22769
22770         DUK_ASSERT_API_ENTRY(thr);
22771
22772         DUK__CHECK_SPACE();
22773
22774         if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
22775                 /* as is */
22776         } else if (nargs == DUK_VARARGS) {
22777                 nargs = DUK_LFUNC_NARGS_VARARGS;
22778         } else {
22779                 goto api_error;
22780         }
22781         if (DUK_UNLIKELY(!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX))) {
22782                 goto api_error;
22783         }
22784         if (DUK_UNLIKELY(!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX))) {
22785                 goto api_error;
22786         }
22787
22788         lf_flags = DUK_LFUNC_FLAGS_PACK((duk_small_int_t) magic, (duk_small_uint_t) length, (duk_small_uint_t) nargs);
22789         tv_slot = thr->valstack_top++;
22790         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_slot));
22791         DUK_TVAL_SET_LIGHTFUNC(tv_slot, func, lf_flags);
22792         DUK_ASSERT(tv_slot >= thr->valstack_bottom);
22793         return (duk_idx_t) (tv_slot - thr->valstack_bottom);
22794
22795  api_error:
22796         DUK_ERROR_TYPE_INVALID_ARGS(thr);
22797         DUK_WO_NORETURN(return 0;);
22798 }
22799
22800 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22801 DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_hthread *thr, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
22802         duk_hbufobj *obj;
22803         duk_tval *tv_slot;
22804
22805         DUK_ASSERT_API_ENTRY(thr);
22806         DUK_ASSERT(prototype_bidx >= 0);
22807
22808         DUK__CHECK_SPACE();
22809
22810         obj = duk_hbufobj_alloc(thr, hobject_flags_and_class);
22811         DUK_ASSERT(obj != NULL);
22812
22813         DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
22814         DUK_ASSERT_HBUFOBJ_VALID(obj);
22815
22816         tv_slot = thr->valstack_top;
22817         DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
22818         DUK_HOBJECT_INCREF(thr, obj);
22819         thr->valstack_top++;
22820
22821         return obj;
22822 }
22823 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
22824
22825 /* XXX: There's quite a bit of overlap with buffer creation handling in
22826  * duk_bi_buffer.c.  Look for overlap and refactor.
22827  */
22828 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22829 #define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,istypedarray) \
22830         (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (istypedarray))
22831
22832 static const duk_uint32_t duk__bufobj_flags_lookup[] = {
22833         /* Node.js Buffers are Uint8Array instances which inherit from Buffer.prototype. */
22834         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER,       DUK_BIDX_ARRAYBUFFER_PROTOTYPE,       DUK_HBUFOBJ_ELEM_UINT8,        0, 0),  /* DUK_BUFOBJ_ARRAYBUFFER */
22835         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY,        DUK_BIDX_NODEJS_BUFFER_PROTOTYPE,     DUK_HBUFOBJ_ELEM_UINT8,        0, 1),  /* DUK_BUFOBJ_NODEJS_BUFFER */
22836         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW,          DUK_BIDX_DATAVIEW_PROTOTYPE,          DUK_HBUFOBJ_ELEM_UINT8,        0, 0),  /* DUK_BUFOBJ_DATAVIEW */
22837         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY,         DUK_BIDX_INT8ARRAY_PROTOTYPE,         DUK_HBUFOBJ_ELEM_INT8,         0, 1),  /* DUK_BUFOBJ_INT8ARRAY */
22838         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY,        DUK_BIDX_UINT8ARRAY_PROTOTYPE,        DUK_HBUFOBJ_ELEM_UINT8,        0, 1),  /* DUK_BUFOBJ_UINT8ARRAY */
22839         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8CLAMPED, 0, 1),  /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
22840         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY,        DUK_BIDX_INT16ARRAY_PROTOTYPE,        DUK_HBUFOBJ_ELEM_INT16,        1, 1),  /* DUK_BUFOBJ_INT16ARRAY */
22841         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY,       DUK_BIDX_UINT16ARRAY_PROTOTYPE,       DUK_HBUFOBJ_ELEM_UINT16,       1, 1),  /* DUK_BUFOBJ_UINT16ARRAY */
22842         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY,        DUK_BIDX_INT32ARRAY_PROTOTYPE,        DUK_HBUFOBJ_ELEM_INT32,        2, 1),  /* DUK_BUFOBJ_INT32ARRAY */
22843         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY,       DUK_BIDX_UINT32ARRAY_PROTOTYPE,       DUK_HBUFOBJ_ELEM_UINT32,       2, 1),  /* DUK_BUFOBJ_UINT32ARRAY */
22844         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY,      DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,      DUK_HBUFOBJ_ELEM_FLOAT32,      2, 1),  /* DUK_BUFOBJ_FLOAT32ARRAY */
22845         DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY,      DUK_BIDX_FLOAT64ARRAY_PROTOTYPE,      DUK_HBUFOBJ_ELEM_FLOAT64,      3, 1)   /* DUK_BUFOBJ_FLOAT64ARRAY */
22846 };
22847 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
22848
22849 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
22850 DUK_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) {
22851         duk_hbufobj *h_bufobj;
22852         duk_hbuffer *h_val;
22853         duk_hobject *h_arraybuf;
22854         duk_uint32_t tmp;
22855         duk_uint_t classnum;
22856         duk_uint_t protobidx;
22857         duk_uint_t lookupidx;
22858         duk_uint_t uint_offset, uint_length, uint_added;
22859
22860         DUK_ASSERT_API_ENTRY(thr);
22861
22862         /* The underlying types for offset/length in duk_hbufobj is
22863          * duk_uint_t; make sure argument values fit.
22864          */
22865         uint_offset = (duk_uint_t) byte_offset;
22866         uint_length = (duk_uint_t) byte_length;
22867         if (sizeof(duk_size_t) != sizeof(duk_uint_t)) {
22868                 if (DUK_UNLIKELY((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length)) {
22869                         goto range_error;
22870                 }
22871         }
22872
22873         DUK_ASSERT_DISABLE(flags >= 0);  /* flags is unsigned */
22874         lookupidx = flags;
22875         if (DUK_UNLIKELY(lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t))) {
22876                 goto arg_error;
22877         }
22878         tmp = duk__bufobj_flags_lookup[lookupidx];
22879         classnum = tmp >> 24;
22880         protobidx = (tmp >> 16) & 0xff;
22881
22882         h_arraybuf = duk_get_hobject(thr, idx_buffer);
22883         if (h_arraybuf != NULL &&  /* argument is an object */
22884             flags != DUK_BUFOBJ_ARRAYBUFFER &&  /* creating a view */
22885             DUK_HOBJECT_GET_CLASS_NUMBER(h_arraybuf) == DUK_HOBJECT_CLASS_ARRAYBUFFER  /* argument is ArrayBuffer */) {
22886                 duk_uint_t tmp_offset;
22887
22888                 DUK_ASSERT_HBUFOBJ_VALID((duk_hbufobj *) h_arraybuf);
22889                 h_val = ((duk_hbufobj *) h_arraybuf)->buf;
22890                 if (DUK_UNLIKELY(h_val == NULL)) {
22891                         goto arg_error;
22892                 }
22893
22894                 tmp_offset = uint_offset + ((duk_hbufobj *) h_arraybuf)->offset;
22895                 if (DUK_UNLIKELY(tmp_offset < uint_offset)) {
22896                         goto range_error;
22897                 }
22898                 uint_offset = tmp_offset;
22899
22900                 /* Note intentional difference to new TypedArray(): we allow
22901                  * caller to create an uncovered typed array (which is memory
22902                  * safe); new TypedArray() rejects it.
22903                  */
22904         } else {
22905                 /* Handle unexpected object arguments here too, for nice error
22906                  * messages.
22907                  */
22908                 h_arraybuf = NULL;
22909                 h_val = duk_require_hbuffer(thr, idx_buffer);
22910         }
22911
22912         /* Wrap check for offset+length. */
22913         uint_added = uint_offset + uint_length;
22914         if (DUK_UNLIKELY(uint_added < uint_offset)) {
22915                 goto range_error;
22916         }
22917         DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
22918
22919         DUK_ASSERT(h_val != NULL);
22920
22921         h_bufobj = duk_push_bufobj_raw(thr,
22922                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
22923                                        DUK_HOBJECT_FLAG_BUFOBJ |
22924                                        DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
22925                                        (duk_small_int_t) protobidx);
22926         DUK_ASSERT(h_bufobj != NULL);
22927
22928         h_bufobj->buf = h_val;
22929         DUK_HBUFFER_INCREF(thr, h_val);
22930         h_bufobj->buf_prop = h_arraybuf;
22931         DUK_HOBJECT_INCREF_ALLOWNULL(thr, h_arraybuf);
22932         h_bufobj->offset = uint_offset;
22933         h_bufobj->length = uint_length;
22934         h_bufobj->shift = (tmp >> 4) & 0x0f;
22935         h_bufobj->elem_type = (tmp >> 8) & 0xff;
22936         h_bufobj->is_typedarray = tmp & 0x0f;
22937         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
22938
22939         /* TypedArray views need an automatic ArrayBuffer which must be
22940          * provided as .buffer property of the view.  The ArrayBuffer is
22941          * referenced via duk_hbufobj->buf_prop and an inherited .buffer
22942          * accessor returns it.  The ArrayBuffer is created lazily on first
22943          * access if necessary so we don't need to do anything more here.
22944          */
22945         return;
22946
22947  range_error:
22948         DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
22949         DUK_WO_NORETURN(return;);
22950
22951  arg_error:
22952         DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS);
22953         DUK_WO_NORETURN(return;);
22954 }
22955 #else  /* DUK_USE_BUFFEROBJECT_SUPPORT */
22956 DUK_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) {
22957         DUK_ASSERT_API_ENTRY(thr);
22958         DUK_UNREF(idx_buffer);
22959         DUK_UNREF(byte_offset);
22960         DUK_UNREF(byte_length);
22961         DUK_UNREF(flags);
22962         DUK_ERROR_UNSUPPORTED(thr);
22963         DUK_WO_NORETURN(return;);
22964 }
22965 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
22966
22967 DUK_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) {
22968         duk_hobject *proto;
22969 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
22970         duk_small_uint_t augment_flags;
22971 #endif
22972
22973         DUK_ASSERT_API_ENTRY(thr);
22974         DUK_ASSERT(thr != NULL);
22975         DUK_UNREF(filename);
22976         DUK_UNREF(line);
22977
22978         /* Error code also packs a tracedata related flag. */
22979 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
22980         augment_flags = 0;
22981         if (err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE) {
22982                 augment_flags = DUK_AUGMENT_FLAG_NOBLAME_FILELINE;
22983         }
22984 #endif
22985         err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
22986
22987         /* error gets its 'name' from the prototype */
22988         proto = duk_error_prototype_from_code(thr, err_code);
22989         (void) duk_push_object_helper_proto(thr,
22990                                             DUK_HOBJECT_FLAG_EXTENSIBLE |
22991                                             DUK_HOBJECT_FLAG_FASTREFS |
22992                                             DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
22993                                             proto);
22994
22995         /* ... and its 'message' from an instance property */
22996         if (fmt) {
22997                 duk_push_vsprintf(thr, fmt, ap);
22998                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
22999         } else {
23000                 /* If no explicit message given, put error code into message field
23001                  * (as a number).  This is not fully in keeping with the ECMAScript
23002                  * error model because messages are supposed to be strings (Error
23003                  * constructors use ToString() on their argument).  However, it's
23004                  * probably more useful than having a separate 'code' property.
23005                  */
23006                 duk_push_int(thr, err_code);
23007                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
23008         }
23009
23010         /* XXX: .code = err_code disabled, not sure if useful */
23011
23012         /* Creation time error augmentation */
23013 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
23014         /* filename may be NULL in which case file/line is not recorded */
23015         duk_err_augment_error_create(thr, thr, filename, line, augment_flags);  /* may throw an error */
23016 #endif
23017
23018         return duk_get_top_index_unsafe(thr);
23019 }
23020
23021 DUK_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, ...) {
23022         va_list ap;
23023         duk_idx_t ret;
23024
23025         DUK_ASSERT_API_ENTRY(thr);
23026
23027         va_start(ap, fmt);
23028         ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
23029         va_end(ap);
23030         return ret;
23031 }
23032
23033 #if !defined(DUK_USE_VARIADIC_MACROS)
23034 DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
23035         const char *filename = duk_api_global_filename;
23036         duk_int_t line = duk_api_global_line;
23037         va_list ap;
23038         duk_idx_t ret;
23039
23040         DUK_ASSERT_API_ENTRY(thr);
23041
23042         duk_api_global_filename = NULL;
23043         duk_api_global_line = 0;
23044         va_start(ap, fmt);
23045         ret = duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
23046         va_end(ap);
23047         return ret;
23048 }
23049 #endif  /* DUK_USE_VARIADIC_MACROS */
23050
23051 DUK_EXTERNAL void *duk_push_buffer_raw(duk_hthread *thr, duk_size_t size, duk_small_uint_t flags) {
23052         duk_tval *tv_slot;
23053         duk_hbuffer *h;
23054         void *buf_data;
23055
23056         DUK_ASSERT_API_ENTRY(thr);
23057
23058         DUK__CHECK_SPACE();
23059
23060         /* Check for maximum buffer length. */
23061         if (DUK_UNLIKELY(size > DUK_HBUFFER_MAX_BYTELEN)) {
23062                 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
23063                 DUK_WO_NORETURN(return NULL;);
23064         }
23065
23066         h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
23067         if (DUK_UNLIKELY(h == NULL)) {
23068                 DUK_ERROR_ALLOC_FAILED(thr);
23069                 DUK_WO_NORETURN(return NULL;);
23070         }
23071
23072         tv_slot = thr->valstack_top;
23073         DUK_TVAL_SET_BUFFER(tv_slot, h);
23074         DUK_HBUFFER_INCREF(thr, h);
23075         thr->valstack_top++;
23076
23077         return (void *) buf_data;
23078 }
23079
23080 DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_hthread *thr, duk_size_t len) {
23081         DUK_ASSERT_API_ENTRY(thr);
23082         return duk_push_buffer_raw(thr, len, DUK_BUF_FLAG_NOZERO);
23083 }
23084
23085 DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_hthread *thr, duk_size_t len) {
23086         void *ptr;
23087
23088         DUK_ASSERT_API_ENTRY(thr);
23089
23090         ptr = duk_push_buffer_raw(thr, len, 0);
23091         DUK_ASSERT(ptr != NULL);
23092 #if !defined(DUK_USE_ZERO_BUFFER_DATA)
23093         /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
23094          * is not set.
23095          */
23096         duk_memzero((void *) ptr, (size_t) len);
23097 #endif
23098         return ptr;
23099 }
23100
23101 #if defined(DUK_USE_ES6_PROXY)
23102 DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
23103         duk_hobject *h_target;
23104         duk_hobject *h_handler;
23105         duk_hproxy *h_proxy;
23106         duk_tval *tv_slot;
23107         duk_uint_t flags;
23108
23109         DUK_ASSERT_API_ENTRY(thr);
23110         DUK_UNREF(proxy_flags);
23111
23112         /* DUK__CHECK_SPACE() unnecessary because the Proxy is written to
23113          * value stack in-place.
23114          */
23115 #if 0
23116         DUK__CHECK_SPACE();
23117 #endif
23118
23119         /* Reject a proxy object as the target because it would need
23120          * special handling in property lookups.  (ES2015 has no such
23121          * restriction.)
23122          */
23123         h_target = duk_require_hobject_promote_mask(thr, -2, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
23124         DUK_ASSERT(h_target != NULL);
23125         if (DUK_HOBJECT_IS_PROXY(h_target)) {
23126                 goto fail_args;
23127         }
23128
23129         /* Reject a proxy object as the handler because it would cause
23130          * potentially unbounded recursion.  (ES2015 has no such
23131          * restriction.)
23132          *
23133          * There's little practical reason to use a lightfunc or a plain
23134          * buffer as the handler table: one could only provide traps via
23135          * their prototype objects (Function.prototype and ArrayBuffer.prototype).
23136          * Even so, as lightfuncs and plain buffers mimic their object
23137          * counterparts, they're promoted and accepted here.
23138          */
23139         h_handler = duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
23140         DUK_ASSERT(h_handler != NULL);
23141         if (DUK_HOBJECT_IS_PROXY(h_handler)) {
23142                 goto fail_args;
23143         }
23144
23145         /* XXX: Proxy object currently has no prototype, so ToPrimitive()
23146          * coercion fails which is a bit confusing.
23147          */
23148
23149         /* CALLABLE and CONSTRUCTABLE flags are copied from the (initial)
23150          * target, see ES2015 Sections 9.5.15 and 9.5.13.
23151          */
23152         flags = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h_target) &
23153                 (DUK_HOBJECT_FLAG_CALLABLE | DUK_HOBJECT_FLAG_CONSTRUCTABLE);
23154         flags |= DUK_HOBJECT_FLAG_EXTENSIBLE |
23155                  DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ;
23156         if (flags & DUK_HOBJECT_FLAG_CALLABLE) {
23157                 flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION) |
23158                          DUK_HOBJECT_FLAG_SPECIAL_CALL;
23159         } else {
23160                 flags |= DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT);
23161         }
23162
23163         h_proxy = duk_hproxy_alloc(thr, flags);
23164         DUK_ASSERT(h_proxy != NULL);
23165         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_proxy) == NULL);
23166
23167         /* Initialize Proxy target and handler references; avoid INCREF
23168          * by stealing the value stack refcounts via direct value stack
23169          * manipulation.  INCREF is needed for the Proxy itself however.
23170          */
23171         DUK_ASSERT(h_target != NULL);
23172         h_proxy->target = h_target;
23173         DUK_ASSERT(h_handler != NULL);
23174         h_proxy->handler = h_handler;
23175         DUK_ASSERT_HPROXY_VALID(h_proxy);
23176
23177         DUK_ASSERT(duk_get_hobject(thr, -2) == h_target);
23178         DUK_ASSERT(duk_get_hobject(thr, -1) == h_handler);
23179         tv_slot = thr->valstack_top - 2;
23180         DUK_ASSERT(tv_slot >= thr->valstack_bottom);
23181         DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) h_proxy);
23182         DUK_HOBJECT_INCREF(thr, (duk_hobject *) h_proxy);
23183         tv_slot++;
23184         DUK_TVAL_SET_UNDEFINED(tv_slot);  /* [ ... target handler ] -> [ ... proxy undefined ] */
23185         thr->valstack_top = tv_slot;      /* -> [ ... proxy ] */
23186
23187         DUK_DD(DUK_DDPRINT("created Proxy: %!iT", duk_get_tval(thr, -1)));
23188
23189         return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom - 1);
23190
23191  fail_args:
23192         DUK_ERROR_TYPE_INVALID_ARGS(thr);
23193         DUK_WO_NORETURN(return 0;);
23194 }
23195 #else  /* DUK_USE_ES6_PROXY */
23196 DUK_EXTERNAL duk_idx_t duk_push_proxy(duk_hthread *thr, duk_uint_t proxy_flags) {
23197         DUK_ASSERT_API_ENTRY(thr);
23198         DUK_UNREF(proxy_flags);
23199         DUK_ERROR_UNSUPPORTED(thr);
23200         DUK_WO_NORETURN(return 0;);
23201 }
23202 #endif  /* DUK_USE_ES6_PROXY */
23203
23204 #if defined(DUK_USE_ASSERTIONS)
23205 DUK_LOCAL void duk__validate_push_heapptr(duk_hthread *thr, void *ptr) {
23206         duk_heaphdr *h;
23207         duk_heaphdr *curr;
23208         duk_bool_t found = 0;
23209
23210         h = (duk_heaphdr *) ptr;
23211         if (h == NULL) {
23212                 /* Allowed. */
23213                 return;
23214         }
23215         DUK_ASSERT(h != NULL);
23216         DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
23217
23218         /* One particular problem case is where an object has been
23219          * queued for finalization but the finalizer hasn't yet been
23220          * executed.
23221          *
23222          * Corner case: we're running in a finalizer for object X, and
23223          * user code calls duk_push_heapptr() for X itself.  In this
23224          * case X will be in finalize_list, and we can detect the case
23225          * by seeing that X's FINALIZED flag is set (which is done before
23226          * the finalizer starts executing).
23227          */
23228 #if defined(DUK_USE_FINALIZER_SUPPORT)
23229         for (curr = thr->heap->finalize_list;
23230              curr != NULL;
23231              curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
23232                 /* FINALIZABLE is set for all objects on finalize_list
23233                  * except for an object being finalized right now.  So
23234                  * can't assert here.
23235                  */
23236 #if 0
23237                 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr));
23238 #endif
23239
23240                 if (curr == h) {
23241                         if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h)) {
23242                                 /* Object is currently being finalized. */
23243                                 DUK_ASSERT(found == 0);  /* Would indicate corrupted lists. */
23244                                 found = 1;
23245                         } else {
23246                                 /* Not being finalized but on finalize_list,
23247                                  * allowed since Duktape 2.1.
23248                                  */
23249                                 DUK_ASSERT(found == 0);  /* Would indicate corrupted lists. */
23250                                 found = 1;
23251                         }
23252                 }
23253         }
23254 #endif  /* DUK_USE_FINALIZER_SUPPORT */
23255
23256 #if defined(DUK_USE_REFERENCE_COUNTING)
23257         /* Because refzero_list is now processed to completion inline with
23258          * no side effects, it's always empty here.
23259          */
23260         DUK_ASSERT(thr->heap->refzero_list == NULL);
23261 #endif
23262
23263         /* If not present in finalize_list (or refzero_list), it
23264          * must be either in heap_allocated or the string table.
23265          */
23266         if (DUK_HEAPHDR_IS_STRING(h)) {
23267                 duk_uint32_t i;
23268                 duk_hstring *str;
23269                 duk_heap *heap = thr->heap;
23270
23271                 DUK_ASSERT(found == 0);
23272                 for (i = 0; i < heap->st_size; i++) {
23273 #if defined(DUK_USE_STRTAB_PTRCOMP)
23274                         str = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]);
23275 #else
23276                         str = heap->strtable[i];
23277 #endif
23278                         while (str != NULL) {
23279                                 if (str == (duk_hstring *) h) {
23280                                         DUK_ASSERT(found == 0);  /* Would indicate corrupted lists. */
23281                                         found = 1;
23282                                         break;
23283                                 }
23284                                 str = str->hdr.h_next;
23285                         }
23286                 }
23287                 DUK_ASSERT(found != 0);
23288         } else {
23289                 for (curr = thr->heap->heap_allocated;
23290                      curr != NULL;
23291                      curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
23292                         if (curr == h) {
23293                                 DUK_ASSERT(found == 0);  /* Would indicate corrupted lists. */
23294                                 found = 1;
23295                         }
23296                 }
23297                 DUK_ASSERT(found != 0);
23298         }
23299 }
23300 #endif  /* DUK_USE_ASSERTIONS */
23301
23302 DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_hthread *thr, void *ptr) {
23303         duk_idx_t ret;
23304         duk_tval *tv;
23305
23306         DUK_ASSERT_API_ENTRY(thr);
23307
23308         /* Reviving an object using a heap pointer is a dangerous API
23309          * operation: if the application doesn't guarantee that the
23310          * pointer target is always reachable, difficult-to-diagnose
23311          * problems may ensue.  Try to validate the 'ptr' argument to
23312          * the extent possible.
23313          */
23314
23315 #if defined(DUK_USE_ASSERTIONS)
23316         duk__validate_push_heapptr(thr, ptr);
23317 #endif
23318
23319         DUK__CHECK_SPACE();
23320
23321         ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
23322         tv = thr->valstack_top++;
23323
23324         if (ptr == NULL) {
23325                 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
23326                 return ret;
23327         }
23328
23329         DUK_ASSERT_HEAPHDR_VALID((duk_heaphdr *) ptr);
23330
23331         /* If the argument is on finalize_list it has technically been
23332          * unreachable before duk_push_heapptr() but it's still safe to
23333          * push it.  Starting from Duktape 2.1 allow application code to
23334          * do so.  There are two main cases:
23335          *
23336          *   (1) The object is on the finalize_list and we're called by
23337          *       the finalizer for the object being finalized.  In this
23338          *       case do nothing: finalize_list handling will deal with
23339          *       the object queueing.  This is detected by the object not
23340          *       having a FINALIZABLE flag despite being on the finalize_list;
23341          *       the flag is cleared for the object being finalized only.
23342          *
23343          *   (2) The object is on the finalize_list but is not currently
23344          *       being processed.  In this case the object can be queued
23345          *       back to heap_allocated with a few flags cleared, in effect
23346          *       cancelling the finalizer.
23347          */
23348         if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) ptr))) {
23349                 duk_heaphdr *curr;
23350
23351                 DUK_D(DUK_DPRINT("duk_push_heapptr() with a pointer on finalize_list, autorescue"));
23352
23353                 curr = (duk_heaphdr *) ptr;
23354                 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
23355
23356                 /* Because FINALIZED is set prior to finalizer call, it will
23357                  * be set for the object being currently finalized, but not
23358                  * for other objects on finalize_list.
23359                  */
23360                 DUK_HEAPHDR_CLEAR_FINALIZED(curr);
23361
23362                 /* Dequeue object from finalize_list and queue it back to
23363                  * heap_allocated.
23364                  */
23365 #if defined(DUK_USE_REFERENCE_COUNTING)
23366                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);  /* Preincremented on finalize_list insert. */
23367                 DUK_HEAPHDR_PREDEC_REFCOUNT(curr);
23368 #endif
23369                 DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(thr->heap, curr);
23370                 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(thr->heap, curr);
23371
23372                 /* Continue with the rest. */
23373         }
23374
23375         switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
23376         case DUK_HTYPE_STRING:
23377                 DUK_TVAL_SET_STRING(tv, (duk_hstring *) ptr);
23378                 break;
23379         case DUK_HTYPE_OBJECT:
23380                 DUK_TVAL_SET_OBJECT(tv, (duk_hobject *) ptr);
23381                 break;
23382         default:
23383                 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr) == DUK_HTYPE_BUFFER);
23384                 DUK_TVAL_SET_BUFFER(tv, (duk_hbuffer *) ptr);
23385                 break;
23386         }
23387
23388         DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) ptr);
23389
23390         return ret;
23391 }
23392
23393 /* Push object with no prototype, i.e. a "bare" object. */
23394 DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_hthread *thr) {
23395         DUK_ASSERT_API_ENTRY(thr);
23396
23397         (void) duk_push_object_helper(thr,
23398                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
23399                                       DUK_HOBJECT_FLAG_FASTREFS |
23400                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
23401                                       -1);  /* no prototype */
23402         return duk_get_top_index_unsafe(thr);
23403 }
23404
23405 DUK_INTERNAL void duk_push_hstring(duk_hthread *thr, duk_hstring *h) {
23406         duk_tval tv;
23407
23408         DUK_ASSERT_API_ENTRY(thr);
23409         DUK_ASSERT(h != NULL);
23410
23411         DUK_TVAL_SET_STRING(&tv, h);
23412         duk_push_tval(thr, &tv);
23413 }
23414
23415 DUK_INTERNAL void duk_push_hstring_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
23416         DUK_ASSERT_API_ENTRY(thr);
23417         DUK_ASSERT_STRIDX_VALID(stridx);
23418         duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
23419 }
23420
23421 DUK_INTERNAL void duk_push_hstring_empty(duk_hthread *thr) {
23422         DUK_ASSERT_API_ENTRY(thr);
23423         duk_push_hstring(thr, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING));
23424 }
23425
23426 DUK_INTERNAL void duk_push_hobject(duk_hthread *thr, duk_hobject *h) {
23427         duk_tval tv;
23428
23429         DUK_ASSERT_API_ENTRY(thr);
23430         DUK_ASSERT(h != NULL);
23431
23432         DUK_TVAL_SET_OBJECT(&tv, h);
23433         duk_push_tval(thr, &tv);
23434 }
23435
23436 DUK_INTERNAL void duk_push_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
23437         duk_tval tv;
23438
23439         DUK_ASSERT_API_ENTRY(thr);
23440         DUK_ASSERT(h != NULL);
23441
23442         DUK_TVAL_SET_BUFFER(&tv, h);
23443         duk_push_tval(thr, &tv);
23444 }
23445
23446 DUK_INTERNAL void duk_push_hobject_bidx(duk_hthread *thr, duk_small_int_t builtin_idx) {
23447         DUK_ASSERT_API_ENTRY(thr);
23448         DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
23449         DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
23450
23451         duk_push_hobject(thr, thr->builtins[builtin_idx]);
23452 }
23453
23454 /*
23455  *  Poppers
23456  */
23457
23458 DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_n_unsafe_raw(duk_hthread *thr, duk_idx_t count) {
23459         duk_tval *tv;
23460 #if defined(DUK_USE_REFERENCE_COUNTING)
23461         duk_tval *tv_end;
23462 #endif
23463
23464         DUK_ASSERT_CTX_VALID(thr);
23465         DUK_ASSERT(count >= 0);
23466         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
23467
23468 #if defined(DUK_USE_REFERENCE_COUNTING)
23469         tv = thr->valstack_top;
23470         tv_end = tv - count;
23471         while (tv != tv_end) {
23472                 tv--;
23473                 DUK_ASSERT(tv >= thr->valstack_bottom);
23474                 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
23475         }
23476         thr->valstack_top = tv;
23477         DUK_REFZERO_CHECK_FAST(thr);
23478 #else
23479         tv = thr->valstack_top;
23480         while (count > 0) {
23481                 count--;
23482                 tv--;
23483                 DUK_ASSERT(tv >= thr->valstack_bottom);
23484                 DUK_TVAL_SET_UNDEFINED(tv);
23485         }
23486         thr->valstack_top = tv;
23487 #endif
23488
23489         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23490 }
23491
23492 DUK_EXTERNAL void duk_pop_n(duk_hthread *thr, duk_idx_t count) {
23493         DUK_ASSERT_API_ENTRY(thr);
23494         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23495
23496         if (DUK_UNLIKELY((duk_uidx_t) (thr->valstack_top - thr->valstack_bottom) < (duk_uidx_t) count)) {
23497                 DUK_ERROR_RANGE_INVALID_COUNT(thr);
23498                 DUK_WO_NORETURN(return;);
23499         }
23500         DUK_ASSERT(count >= 0);
23501
23502         duk__pop_n_unsafe_raw(thr, count);
23503 }
23504
23505 #if defined(DUK_USE_PREFER_SIZE)
23506 DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
23507         DUK_ASSERT_API_ENTRY(thr);
23508         duk_pop_n(thr, count);
23509 }
23510 #else  /* DUK_USE_PREFER_SIZE */
23511 DUK_INTERNAL void duk_pop_n_unsafe(duk_hthread *thr, duk_idx_t count) {
23512         DUK_ASSERT_API_ENTRY(thr);
23513         duk__pop_n_unsafe_raw(thr, count);
23514 }
23515 #endif  /* DUK_USE_PREFER_SIZE */
23516
23517 /* Pop N elements without DECREF (in effect "stealing" any actual refcounts). */
23518 #if defined(DUK_USE_REFERENCE_COUNTING)
23519 DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
23520         duk_tval *tv;
23521
23522         DUK_ASSERT_API_ENTRY(thr);
23523         DUK_ASSERT(count >= 0);
23524         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23525         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) count);
23526
23527         tv = thr->valstack_top;
23528         while (count > 0) {
23529                 count--;
23530                 tv--;
23531                 DUK_ASSERT(tv >= thr->valstack_bottom);
23532                 DUK_TVAL_SET_UNDEFINED(tv);
23533         }
23534         thr->valstack_top = tv;
23535
23536         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23537 }
23538 #else  /* DUK_USE_REFERENCE_COUNTING */
23539 DUK_INTERNAL void duk_pop_n_nodecref_unsafe(duk_hthread *thr, duk_idx_t count) {
23540         DUK_ASSERT_API_ENTRY(thr);
23541         duk_pop_n_unsafe(thr, count);
23542 }
23543 #endif  /* DUK_USE_REFERENCE_COUNTING */
23544
23545 /* Popping one element is called so often that when footprint is not an issue,
23546  * compile a specialized function for it.
23547  */
23548 #if defined(DUK_USE_PREFER_SIZE)
23549 DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
23550         DUK_ASSERT_API_ENTRY(thr);
23551         duk_pop_n(thr, 1);
23552 }
23553 DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
23554         DUK_ASSERT_API_ENTRY(thr);
23555         duk_pop_n_unsafe(thr, 1);
23556 }
23557 DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
23558         DUK_ASSERT_API_ENTRY(thr);
23559         duk_pop_n_nodecref_unsafe(thr, 1);
23560 }
23561 #else  /* DUK_USE_PREFER_SIZE */
23562 DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_unsafe_raw(duk_hthread *thr) {
23563         duk_tval *tv;
23564
23565         DUK_ASSERT_CTX_VALID(thr);
23566         DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
23567         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23568         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
23569
23570         tv = --thr->valstack_top;
23571         DUK_ASSERT(tv >= thr->valstack_bottom);
23572 #if defined(DUK_USE_REFERENCE_COUNTING)
23573         DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);  /* side effects */
23574 #else
23575         DUK_TVAL_SET_UNDEFINED(tv);
23576 #endif
23577
23578         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23579 }
23580 DUK_EXTERNAL void duk_pop(duk_hthread *thr) {
23581         DUK_ASSERT_API_ENTRY(thr);
23582
23583         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23584         if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
23585                 DUK_ERROR_RANGE_INVALID_COUNT(thr);
23586                 DUK_WO_NORETURN(return;);
23587         }
23588
23589         duk__pop_unsafe_raw(thr);
23590 }
23591 DUK_INTERNAL void duk_pop_unsafe(duk_hthread *thr) {
23592         DUK_ASSERT_API_ENTRY(thr);
23593         duk__pop_unsafe_raw(thr);
23594 }
23595 DUK_INTERNAL void duk_pop_nodecref_unsafe(duk_hthread *thr) {
23596         duk_tval *tv;
23597
23598         DUK_ASSERT_API_ENTRY(thr);
23599         DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
23600         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23601         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
23602
23603         tv = --thr->valstack_top;
23604         DUK_ASSERT(tv >= thr->valstack_bottom);
23605         DUK_TVAL_SET_UNDEFINED(tv);
23606
23607         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23608 }
23609 #endif  /* !DUK_USE_PREFER_SIZE */
23610
23611 #if defined(DUK_USE_PREFER_SIZE)
23612 DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
23613         DUK_ASSERT_API_ENTRY(thr);
23614         duk_pop_nodecref_unsafe(thr);
23615 }
23616 #else  /* DUK_USE_PREFER_SIZE */
23617 DUK_INTERNAL void duk_pop_undefined(duk_hthread *thr) {
23618         DUK_ASSERT_API_ENTRY(thr);
23619         DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
23620         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23621         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 1);
23622
23623         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
23624         thr->valstack_top--;
23625
23626         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23627 }
23628 #endif  /* !DUK_USE_PREFER_SIZE */
23629
23630 #if defined(DUK_USE_PREFER_SIZE)
23631 DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
23632         DUK_ASSERT_API_ENTRY(thr);
23633         duk_pop_n(thr, 2);
23634 }
23635 DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
23636         DUK_ASSERT_API_ENTRY(thr);
23637         duk_pop_n_unsafe(thr, 2);
23638 }
23639 DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
23640         DUK_ASSERT_API_ENTRY(thr);
23641         duk_pop_n_nodecref_unsafe(thr, 2);
23642 }
23643 #else
23644 DUK_LOCAL DUK_ALWAYS_INLINE void duk__pop_2_unsafe_raw(duk_hthread *thr) {
23645         duk_tval *tv;
23646
23647         DUK_ASSERT_CTX_VALID(thr);
23648         DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
23649         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23650         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
23651
23652         tv = --thr->valstack_top;
23653         DUK_ASSERT(tv >= thr->valstack_bottom);
23654 #if defined(DUK_USE_REFERENCE_COUNTING)
23655         DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);  /* side effects */
23656 #else
23657         DUK_TVAL_SET_UNDEFINED(tv);
23658 #endif
23659         tv = --thr->valstack_top;
23660         DUK_ASSERT(tv >= thr->valstack_bottom);
23661 #if defined(DUK_USE_REFERENCE_COUNTING)
23662         DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);  /* side effects */
23663 #else
23664         DUK_TVAL_SET_UNDEFINED(tv);
23665 #endif
23666
23667         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23668 }
23669 DUK_EXTERNAL void duk_pop_2(duk_hthread *thr) {
23670         DUK_ASSERT_API_ENTRY(thr);
23671
23672         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23673         if (DUK_UNLIKELY(thr->valstack_top - 2 < thr->valstack_bottom)) {
23674                 DUK_ERROR_RANGE_INVALID_COUNT(thr);
23675                 DUK_WO_NORETURN(return;);
23676         }
23677
23678         duk__pop_2_unsafe_raw(thr);
23679 }
23680 DUK_INTERNAL void duk_pop_2_unsafe(duk_hthread *thr) {
23681         DUK_ASSERT_API_ENTRY(thr);
23682         duk__pop_2_unsafe_raw(thr);
23683 }
23684 DUK_INTERNAL void duk_pop_2_nodecref_unsafe(duk_hthread *thr) {
23685         DUK_ASSERT_API_ENTRY(thr);
23686         DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
23687         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23688         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) >= (duk_size_t) 2);
23689
23690         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
23691         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 2));
23692         thr->valstack_top -= 2;
23693
23694         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23695 }
23696 #endif  /* !DUK_USE_PREFER_SIZE */
23697
23698 DUK_EXTERNAL void duk_pop_3(duk_hthread *thr) {
23699         DUK_ASSERT_API_ENTRY(thr);
23700         duk_pop_n(thr, 3);
23701 }
23702
23703 DUK_INTERNAL void duk_pop_3_unsafe(duk_hthread *thr) {
23704         DUK_ASSERT_API_ENTRY(thr);
23705         duk_pop_n_unsafe(thr, 3);
23706 }
23707
23708 DUK_INTERNAL void duk_pop_3_nodecref_unsafe(duk_hthread *thr) {
23709         DUK_ASSERT_API_ENTRY(thr);
23710         duk_pop_n_nodecref_unsafe(thr, 3);
23711 }
23712
23713 /*
23714  *  Pack and unpack (pack value stack entries into an array and vice versa)
23715  */
23716
23717 /* XXX: pack index range? array index offset? */
23718 DUK_INTERNAL void duk_pack(duk_hthread *thr, duk_idx_t count) {
23719         duk_tval *tv_src;
23720         duk_tval *tv_dst;
23721         duk_tval *tv_curr;
23722         duk_tval *tv_limit;
23723         duk_idx_t top;
23724
23725         DUK_ASSERT_API_ENTRY(thr);
23726
23727         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23728         top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
23729         DUK_ASSERT(top >= 0);
23730         if (DUK_UNLIKELY((duk_uidx_t) count > (duk_uidx_t) top)) {
23731                 /* Also handles negative count. */
23732                 DUK_ERROR_RANGE_INVALID_COUNT(thr);
23733                 DUK_WO_NORETURN(return;);
23734         }
23735         DUK_ASSERT(count >= 0);
23736
23737         /* Wrapping is controlled by the check above: value stack top can be
23738          * at most DUK_USE_VALSTACK_LIMIT which is low enough so that
23739          * multiplying with sizeof(duk_tval) won't wrap.
23740          */
23741         DUK_ASSERT(count >= 0 && count <= (duk_idx_t) DUK_USE_VALSTACK_LIMIT);
23742         DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval));  /* no wrapping */
23743
23744         tv_dst = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count);  /* XXX: uninitialized would be OK */
23745         DUK_ASSERT(count == 0 || tv_dst != NULL);
23746
23747         /* Copy value stack values directly to the array part without
23748          * any refcount updates: net refcount changes are zero.
23749          */
23750         tv_src = thr->valstack_top - count - 1;
23751         duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
23752
23753         /* Overwrite result array to final value stack location and wipe
23754          * the rest; no refcount operations needed.
23755          */
23756
23757         tv_dst = tv_src;  /* when count == 0, same as tv_src (OK) */
23758         tv_src = thr->valstack_top - 1;
23759         DUK_TVAL_SET_TVAL(tv_dst, tv_src);
23760
23761         /* XXX: internal helper to wipe a value stack segment? */
23762         tv_curr = tv_dst + 1;
23763         tv_limit = thr->valstack_top;
23764         while (tv_curr != tv_limit) {
23765                 /* Wipe policy: keep as 'undefined'. */
23766                 DUK_TVAL_SET_UNDEFINED(tv_curr);
23767                 tv_curr++;
23768         }
23769         thr->valstack_top = tv_dst + 1;
23770 }
23771
23772 DUK_INTERNAL duk_idx_t duk_unpack_array_like(duk_hthread *thr, duk_idx_t idx) {
23773         duk_tval *tv;
23774
23775         DUK_ASSERT_API_ENTRY(thr);
23776
23777         tv = duk_require_tval(thr, idx);
23778         if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv))) {
23779                 duk_hobject *h;
23780                 duk_uint32_t len;
23781                 duk_uint32_t i;
23782
23783                 h = DUK_TVAL_GET_OBJECT(tv);
23784                 DUK_ASSERT(h != NULL);
23785                 DUK_UNREF(h);
23786
23787 #if defined(DUK_USE_ARRAY_FASTPATH)  /* close enough */
23788                 if (DUK_LIKELY(DUK_HOBJECT_IS_ARRAY(h) &&
23789                                ((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h))) {
23790                         duk_harray *h_arr;
23791                         duk_tval *tv_src;
23792                         duk_tval *tv_dst;
23793
23794                         h_arr = (duk_harray *) h;
23795                         len = h_arr->length;
23796                         if (DUK_UNLIKELY(len >= 0x80000000UL)) {
23797                                 goto fail_over_2g;
23798                         }
23799                         duk_require_stack(thr, (duk_idx_t) len);
23800
23801                         /* The potential allocation in duk_require_stack() may
23802                          * run a finalizer which modifies the argArray so that
23803                          * e.g. becomes sparse.  So, we need to recheck that the
23804                          * array didn't change size and that there's still a
23805                          * valid backing array part.
23806                          *
23807                          * XXX: alternatively, could prevent finalizers for the
23808                          * duration.
23809                          */
23810                         if (DUK_UNLIKELY(len != h_arr->length ||
23811                                          h_arr->length > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr))) {
23812                                 goto skip_fast;
23813                         }
23814
23815                         /* Main fast path: arguments array is almost always
23816                          * an actual array (though it might also be an arguments
23817                          * object).
23818                          */
23819
23820                         DUK_DDD(DUK_DDDPRINT("fast path for %ld elements", (long) h_arr->length));
23821                         tv_src = DUK_HOBJECT_A_GET_BASE(thr->heap, h);
23822                         tv_dst = thr->valstack_top;
23823                         while (len-- > 0) {
23824                                 DUK_ASSERT(tv_dst < thr->valstack_end);
23825                                 if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_src))) {
23826                                         /* Gaps are very unlikely.  Skip over them,
23827                                          * without an ancestor lookup (technically
23828                                          * not compliant).
23829                                          */
23830                                         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_dst));  /* valstack policy */
23831                                 } else {
23832                                         DUK_TVAL_SET_TVAL(tv_dst, tv_src);
23833                                         DUK_TVAL_INCREF(thr, tv_dst);
23834                                 }
23835                                 tv_src++;
23836                                 tv_dst++;
23837                         }
23838                         DUK_ASSERT(tv_dst <= thr->valstack_end);
23839                         thr->valstack_top = tv_dst;
23840                         return (duk_idx_t) h_arr->length;
23841                 }
23842          skip_fast:
23843 #endif  /* DUK_USE_ARRAY_FASTPATH */
23844
23845                 /* Slow path: actual lookups.  The initial 'length' lookup
23846                  * decides the output length, regardless of side effects that
23847                  * may resize or change the argArray while we read the
23848                  * indices.
23849                  */
23850                 idx = duk_normalize_index(thr, idx);
23851                 duk_get_prop_stridx(thr, idx, DUK_STRIDX_LENGTH);
23852                 len = duk_to_uint32(thr, -1);  /* ToUint32() coercion required */
23853                 if (DUK_UNLIKELY(len >= 0x80000000UL)) {
23854                         goto fail_over_2g;
23855                 }
23856                 duk_pop_unsafe(thr);
23857                 DUK_DDD(DUK_DDDPRINT("slow path for %ld elements", (long) len));
23858
23859                 duk_require_stack(thr, (duk_idx_t) len);
23860                 for (i = 0; i < len; i++) {
23861                         duk_get_prop_index(thr, idx, (duk_uarridx_t) i);
23862                 }
23863                 return (duk_idx_t) len;
23864         } else if (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv)) {
23865                 return 0;
23866         }
23867
23868         DUK_ERROR_TYPE_INVALID_ARGS(thr);
23869         DUK_WO_NORETURN(return 0;);
23870
23871  fail_over_2g:
23872         DUK_ERROR_RANGE_INVALID_LENGTH(thr);
23873         DUK_WO_NORETURN(return 0;);
23874 }
23875
23876 /*
23877  *  Error throwing
23878  */
23879
23880 DUK_EXTERNAL void duk_throw_raw(duk_hthread *thr) {
23881         duk_tval *tv_val;
23882
23883         DUK_ASSERT_API_ENTRY(thr);
23884         DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
23885         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
23886         DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
23887
23888         if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
23889                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
23890                 DUK_WO_NORETURN(return;);
23891         }
23892
23893         /* Errors are augmented when they are created, not when they are
23894          * thrown or re-thrown.  The current error handler, however, runs
23895          * just before an error is thrown.
23896          */
23897
23898         /* Sync so that augmentation sees up-to-date activations, NULL
23899          * thr->ptr_curr_pc so that it's not used if side effects occur
23900          * in augmentation or longjmp handling.
23901          */
23902         duk_hthread_sync_and_null_currpc(thr);
23903
23904 #if defined(DUK_USE_AUGMENT_ERROR_THROW)
23905         DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
23906         duk_err_augment_error_throw(thr);
23907 #endif
23908         DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(thr, -1)));
23909
23910         tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
23911         duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, tv_val);
23912 #if defined(DUK_USE_DEBUGGER_SUPPORT)
23913         duk_err_check_debugger_integration(thr);
23914 #endif
23915
23916         /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
23917          * need to check that here.  If the value is NULL, a fatal error occurs
23918          * because we can't return.
23919          */
23920
23921         duk_err_longjmp(thr);
23922         DUK_UNREACHABLE();
23923 }
23924
23925 DUK_EXTERNAL void duk_fatal_raw(duk_hthread *thr, const char *err_msg) {
23926         DUK_ASSERT_API_ENTRY(thr);
23927         DUK_ASSERT(thr != NULL);
23928         DUK_ASSERT(thr->heap != NULL);
23929         DUK_ASSERT(thr->heap->fatal_func != NULL);
23930
23931         DUK_D(DUK_DPRINT("fatal error occurred: %s", err_msg ? err_msg : "NULL"));
23932
23933         /* fatal_func should be noreturn, but noreturn declarations on function
23934          * pointers has a very spotty support apparently so it's not currently
23935          * done.
23936          */
23937         thr->heap->fatal_func(thr->heap->heap_udata, err_msg);
23938
23939         /* If the fatal handler returns, all bets are off.  It'd be nice to
23940          * print something here but since we don't want to depend on stdio,
23941          * there's no way to do so portably.
23942          */
23943         DUK_D(DUK_DPRINT("fatal error handler returned, all bets are off!"));
23944         for (;;) {
23945                 /* loop forever, don't return (function marked noreturn) */
23946         }
23947 }
23948
23949 DUK_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) {
23950         DUK_ASSERT_API_ENTRY(thr);
23951
23952         duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
23953         (void) duk_throw(thr);
23954         DUK_WO_NORETURN(return;);
23955 }
23956
23957 DUK_EXTERNAL void duk_error_raw(duk_hthread *thr, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
23958         va_list ap;
23959
23960         DUK_ASSERT_API_ENTRY(thr);
23961
23962         va_start(ap, fmt);
23963         duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
23964         va_end(ap);
23965         (void) duk_throw(thr);
23966         DUK_WO_NORETURN(return;);
23967 }
23968
23969 #if !defined(DUK_USE_VARIADIC_MACROS)
23970 DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap));
23971
23972 DUK_LOCAL void duk__throw_error_from_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, va_list ap) {
23973         const char *filename;
23974         duk_int_t line;
23975
23976         DUK_ASSERT_CTX_VALID(thr);
23977
23978         filename = duk_api_global_filename;
23979         line = duk_api_global_line;
23980         duk_api_global_filename = NULL;
23981         duk_api_global_line = 0;
23982
23983         duk_push_error_object_va_raw(thr, err_code, filename, line, fmt, ap);
23984         (void) duk_throw(thr);
23985         DUK_WO_NORETURN(return;);
23986 }
23987
23988 #define DUK__ERROR_STASH_SHARED(code) do { \
23989                 va_list ap; \
23990                 va_start(ap, fmt); \
23991                 duk__throw_error_from_stash(thr, (code), fmt, ap); \
23992                 va_end(ap); \
23993                 DUK_WO_NORETURN(return 0;); \
23994         } while (0)
23995
23996 DUK_EXTERNAL duk_ret_t duk_error_stash(duk_hthread *thr, duk_errcode_t err_code, const char *fmt, ...) {
23997         DUK_ASSERT_API_ENTRY(thr);
23998         DUK__ERROR_STASH_SHARED(err_code);
23999 }
24000 DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_hthread *thr, const char *fmt, ...) {
24001         DUK_ASSERT_API_ENTRY(thr);
24002         DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR);
24003 }
24004 DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_hthread *thr, const char *fmt, ...) {
24005         DUK_ASSERT_API_ENTRY(thr);
24006         DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR);
24007 }
24008 DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_hthread *thr, const char *fmt, ...) {
24009         DUK_ASSERT_API_ENTRY(thr);
24010         DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR);
24011 }
24012 DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_hthread *thr, const char *fmt, ...) {
24013         DUK_ASSERT_API_ENTRY(thr);
24014         DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR);
24015 }
24016 DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_hthread *thr, const char *fmt, ...) {
24017         DUK_ASSERT_API_ENTRY(thr);
24018         DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR);
24019 }
24020 DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_hthread *thr, const char *fmt, ...) {
24021         DUK_ASSERT_API_ENTRY(thr);
24022         DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR);
24023 }
24024 DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_hthread *thr, const char *fmt, ...) {
24025         DUK_ASSERT_API_ENTRY(thr);
24026         DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR);
24027 }
24028 #endif  /* DUK_USE_VARIADIC_MACROS */
24029
24030 /*
24031  *  Comparison
24032  */
24033
24034 DUK_EXTERNAL duk_bool_t duk_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
24035         duk_tval *tv1, *tv2;
24036
24037         DUK_ASSERT_API_ENTRY(thr);
24038
24039         tv1 = duk_get_tval(thr, idx1);
24040         tv2 = duk_get_tval(thr, idx2);
24041         if ((tv1 == NULL) || (tv2 == NULL)) {
24042                 return 0;
24043         }
24044
24045         /* Coercion may be needed, the helper handles that by pushing the
24046          * tagged values to the stack.
24047          */
24048         return duk_js_equals(thr, tv1, tv2);
24049 }
24050
24051 DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
24052         duk_tval *tv1, *tv2;
24053
24054         DUK_ASSERT_API_ENTRY(thr);
24055
24056         tv1 = duk_get_tval(thr, idx1);
24057         tv2 = duk_get_tval(thr, idx2);
24058         if ((tv1 == NULL) || (tv2 == NULL)) {
24059                 return 0;
24060         }
24061
24062         /* No coercions or other side effects, so safe */
24063         return duk_js_strict_equals(tv1, tv2);
24064 }
24065
24066 DUK_EXTERNAL duk_bool_t duk_samevalue(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
24067         duk_tval *tv1, *tv2;
24068
24069         DUK_ASSERT_API_ENTRY(thr);
24070
24071         tv1 = duk_get_tval(thr, idx1);
24072         tv2 = duk_get_tval(thr, idx2);
24073         if ((tv1 == NULL) || (tv2 == NULL)) {
24074                 return 0;
24075         }
24076
24077         /* No coercions or other side effects, so safe */
24078         return duk_js_samevalue(tv1, tv2);
24079 }
24080
24081 /*
24082  *  instanceof
24083  */
24084
24085 DUK_EXTERNAL duk_bool_t duk_instanceof(duk_hthread *thr, duk_idx_t idx1, duk_idx_t idx2) {
24086         duk_tval *tv1, *tv2;
24087
24088         DUK_ASSERT_API_ENTRY(thr);
24089
24090         /* Index validation is strict, which differs from duk_equals().
24091          * The strict behavior mimics how instanceof itself works, e.g.
24092          * it is a TypeError if rval is not a -callable- object.  It would
24093          * be somewhat inconsistent if rval would be allowed to be
24094          * non-existent without a TypeError.
24095          */
24096         tv1 = duk_require_tval(thr, idx1);
24097         DUK_ASSERT(tv1 != NULL);
24098         tv2 = duk_require_tval(thr, idx2);
24099         DUK_ASSERT(tv2 != NULL);
24100
24101         return duk_js_instanceof(thr, tv1, tv2);
24102 }
24103
24104 /*
24105  *  Lightfunc
24106  */
24107
24108 DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_hthread *thr, duk_c_function func, duk_small_uint_t lf_flags) {
24109         /* Lightfunc name, includes Duktape/C native function pointer, which
24110          * can often be used to locate the function from a symbol table.
24111          * The name also includes the 16-bit duk_tval flags field because it
24112          * includes the magic value.  Because a single native function often
24113          * provides different functionality depending on the magic value, it
24114          * seems reasonably to include it in the name.
24115          *
24116          * On the other hand, a complicated name increases string table
24117          * pressure in low memory environments (but only when function name
24118          * is accessed).
24119          */
24120
24121         DUK_ASSERT_API_ENTRY(thr);
24122
24123         duk_push_literal(thr, "light_");
24124         duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
24125         duk_push_sprintf(thr, "_%04x", (unsigned int) lf_flags);
24126         duk_concat(thr, 3);
24127 }
24128
24129 DUK_INTERNAL void duk_push_lightfunc_name(duk_hthread *thr, duk_tval *tv) {
24130         duk_c_function func;
24131         duk_small_uint_t lf_flags;
24132
24133         DUK_ASSERT_API_ENTRY(thr);
24134         DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
24135
24136         DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
24137         duk_push_lightfunc_name_raw(thr, func, lf_flags);
24138 }
24139
24140 DUK_INTERNAL void duk_push_lightfunc_tostring(duk_hthread *thr, duk_tval *tv) {
24141         duk_c_function func;
24142         duk_small_uint_t lf_flags;
24143
24144         DUK_ASSERT_API_ENTRY(thr);
24145         DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
24146
24147         DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);  /* read before 'tv' potentially invalidated */
24148         duk_push_literal(thr, "function ");
24149         duk_push_lightfunc_name_raw(thr, func, lf_flags);
24150         duk_push_literal(thr, "() { [lightfunc code] }");
24151         duk_concat(thr, 3);
24152 }
24153
24154 /*
24155  *  Function pointers
24156  *
24157  *  Printing function pointers is non-portable, so we do that by hex printing
24158  *  bytes from memory.
24159  */
24160
24161 DUK_INTERNAL void duk_push_string_funcptr(duk_hthread *thr, duk_uint8_t *ptr, duk_size_t sz) {
24162         duk_uint8_t buf[32 * 2];
24163         duk_uint8_t *p, *q;
24164         duk_small_uint_t i;
24165         duk_small_uint_t t;
24166
24167         DUK_ASSERT_API_ENTRY(thr);
24168         DUK_ASSERT(sz <= 32);  /* sanity limit for function pointer size */
24169
24170         p = buf;
24171 #if defined(DUK_USE_INTEGER_LE)
24172         q = ptr + sz;
24173 #else
24174         q = ptr;
24175 #endif
24176         for (i = 0; i < sz; i++) {
24177 #if defined(DUK_USE_INTEGER_LE)
24178                 t = *(--q);
24179 #else
24180                 t = *(q++);
24181 #endif
24182                 *p++ = duk_lc_digits[t >> 4];
24183                 *p++ = duk_lc_digits[t & 0x0f];
24184         }
24185
24186         duk_push_lstring(thr, (const char *) buf, sz * 2);
24187 }
24188
24189 /*
24190  *  Push readable string summarizing duk_tval.  The operation is side effect
24191  *  free and will only throw from internal errors (e.g. out of memory).
24192  *  This is used by e.g. property access code to summarize a key/base safely,
24193  *  and is not intended to be fast (but small and safe).
24194  */
24195
24196 /* String limits for summary strings. */
24197 #define DUK__READABLE_SUMMARY_MAXCHARS 96  /* maximum supported by helper */
24198 #define DUK__READABLE_STRING_MAXCHARS  32  /* for strings/symbols */
24199 #define DUK__READABLE_ERRMSG_MAXCHARS  96  /* for error messages */
24200
24201 /* String sanitizer which escapes ASCII control characters and a few other
24202  * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
24203  * question marks.  No errors are thrown for any input string, except in out
24204  * of memory situations.
24205  */
24206 DUK_LOCAL void duk__push_hstring_readable_unicode(duk_hthread *thr, duk_hstring *h_input, duk_small_uint_t maxchars) {
24207         const duk_uint8_t *p, *p_start, *p_end;
24208         duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_SUMMARY_MAXCHARS +
24209                         2 /*quotes*/ + 3 /*periods*/];
24210         duk_uint8_t *q;
24211         duk_ucodepoint_t cp;
24212         duk_small_uint_t nchars;
24213
24214         DUK_ASSERT_CTX_VALID(thr);
24215         DUK_ASSERT(h_input != NULL);
24216         DUK_ASSERT(maxchars <= DUK__READABLE_SUMMARY_MAXCHARS);
24217
24218         p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
24219         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
24220         p = p_start;
24221         q = buf;
24222
24223         nchars = 0;
24224         *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
24225         for (;;) {
24226                 if (p >= p_end) {
24227                         break;
24228                 }
24229                 if (nchars == maxchars) {
24230                         *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
24231                         *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
24232                         *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
24233                         break;
24234                 }
24235                 if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
24236                         if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) {
24237                                 DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4);  /* estimate is valid */
24238                                 DUK_ASSERT((cp >> 4) <= 0x0f);
24239                                 *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH;
24240                                 *q++ = (duk_uint8_t) DUK_ASC_LC_X;
24241                                 *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4];
24242                                 *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f];
24243                         } else {
24244                                 q += duk_unicode_encode_xutf8(cp, q);
24245                         }
24246                 } else {
24247                         p++;  /* advance manually */
24248                         *q++ = (duk_uint8_t) DUK_ASC_QUESTION;
24249                 }
24250                 nchars++;
24251         }
24252         *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
24253
24254         duk_push_lstring(thr, (const char *) buf, (duk_size_t) (q - buf));
24255 }
24256
24257 DUK_LOCAL const char *duk__push_string_tval_readable(duk_hthread *thr, duk_tval *tv, duk_bool_t error_aware) {
24258         DUK_ASSERT_CTX_VALID(thr);
24259         /* 'tv' may be NULL */
24260
24261         if (tv == NULL) {
24262                 duk_push_literal(thr, "none");
24263         } else {
24264                 switch (DUK_TVAL_GET_TAG(tv)) {
24265                 case DUK_TAG_STRING: {
24266                         duk_hstring *h = DUK_TVAL_GET_STRING(tv);
24267                         if (DUK_HSTRING_HAS_SYMBOL(h)) {
24268                                 /* XXX: string summary produces question marks
24269                                  * so this is not very ideal.
24270                                  */
24271                                 duk_push_literal(thr, "[Symbol ");
24272                                 duk_push_string(thr, duk__get_symbol_type_string(h));
24273                                 duk_push_literal(thr, " ");
24274                                 duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
24275                                 duk_push_literal(thr, "]");
24276                                 duk_concat(thr, 5);
24277                                 break;
24278                         }
24279                         duk__push_hstring_readable_unicode(thr, h, DUK__READABLE_STRING_MAXCHARS);
24280                         break;
24281                 }
24282                 case DUK_TAG_OBJECT: {
24283                         duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
24284                         DUK_ASSERT(h != NULL);
24285
24286                         if (error_aware &&
24287                             duk_hobject_prototype_chain_contains(thr, h, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
24288                                 /* Get error message in a side effect free way if
24289                                  * possible; if not, summarize as a generic object.
24290                                  * Error message currently gets quoted.
24291                                  */
24292                                 /* XXX: better internal getprop call; get without side effects
24293                                  * but traverse inheritance chain.
24294                                  */
24295                                 duk_tval *tv_msg;
24296                                 tv_msg = duk_hobject_find_existing_entry_tval_ptr(thr->heap, h, DUK_HTHREAD_STRING_MESSAGE(thr));
24297                                 if (tv_msg != NULL && DUK_TVAL_IS_STRING(tv_msg)) {
24298                                         /* It's critical to avoid recursion so
24299                                          * only summarize a string .message.
24300                                          */
24301                                         duk__push_hstring_readable_unicode(thr, DUK_TVAL_GET_STRING(tv_msg), DUK__READABLE_ERRMSG_MAXCHARS);
24302                                         break;
24303                                 }
24304                         }
24305                         duk_push_class_string_tval(thr, tv, 1 /*avoid_side_effects*/);
24306                         break;
24307                 }
24308                 case DUK_TAG_BUFFER: {
24309                         /* While plain buffers mimic Uint8Arrays, they summarize differently.
24310                          * This is useful so that the summarized string accurately reflects the
24311                          * internal type which may matter for figuring out bugs etc.
24312                          */
24313                         /* XXX: Hex encoded, length limited buffer summary here? */
24314                         duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
24315                         DUK_ASSERT(h != NULL);
24316                         duk_push_sprintf(thr, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
24317                         break;
24318                 }
24319                 case DUK_TAG_POINTER: {
24320                         /* Surround with parentheses like in JX, ensures NULL pointer
24321                          * is distinguishable from null value ("(null)" vs "null").
24322                          */
24323                         duk_push_tval(thr, tv);
24324                         duk_push_sprintf(thr, "(%s)", duk_to_string(thr, -1));
24325                         duk_remove_m2(thr);
24326                         break;
24327                 }
24328                 default: {
24329                         duk_push_tval(thr, tv);
24330                         break;
24331                 }
24332                 }
24333         }
24334
24335         return duk_to_string(thr, -1);
24336 }
24337 DUK_INTERNAL const char *duk_push_string_tval_readable(duk_hthread *thr, duk_tval *tv) {
24338         DUK_ASSERT_API_ENTRY(thr);
24339         return duk__push_string_tval_readable(thr, tv, 0 /*error_aware*/);
24340 }
24341
24342 DUK_INTERNAL const char *duk_push_string_readable(duk_hthread *thr, duk_idx_t idx) {
24343         DUK_ASSERT_API_ENTRY(thr);
24344         return duk_push_string_tval_readable(thr, duk_get_tval(thr, idx));
24345 }
24346
24347 DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_hthread *thr, duk_tval *tv) {
24348         DUK_ASSERT_API_ENTRY(thr);
24349         return duk__push_string_tval_readable(thr, tv, 1 /*error_aware*/);
24350 }
24351
24352 DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_hthread *thr, duk_hstring *h) {
24353         const duk_uint8_t *p;
24354         const duk_uint8_t *p_end;
24355         const duk_uint8_t *q;
24356
24357         DUK_ASSERT_API_ENTRY(thr);
24358
24359         /* .toString() */
24360         duk_push_literal(thr, "Symbol(");
24361         p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
24362         p_end = p + DUK_HSTRING_GET_BYTELEN(h);
24363         DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80);
24364         p++;
24365         for (q = p; q < p_end; q++) {
24366                 if (*q == 0xffU) {
24367                         /* Terminate either at end-of-string (but NUL MUST
24368                          * be accepted without terminating description) or
24369                          * 0xFF, which is used to mark start of unique trailer
24370                          * (and cannot occur in CESU-8 / extended UTF-8).
24371                          */
24372                         break;
24373                 }
24374         }
24375         duk_push_lstring(thr, (const char *) p, (duk_size_t) (q - p));
24376         duk_push_literal(thr, ")");
24377         duk_concat(thr, 3);
24378 }
24379
24380 /*
24381  *  Functions
24382  */
24383
24384 #if 0  /* not used yet */
24385 DUK_INTERNAL void duk_push_hnatfunc_name(duk_hthread *thr, duk_hnatfunc *h) {
24386         duk_c_function func;
24387
24388         DUK_ASSERT_API_ENTRY(thr);
24389         DUK_ASSERT(h != NULL);
24390         DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h));
24391
24392         duk_push_sprintf(thr, "native_");
24393         func = h->func;
24394         duk_push_string_funcptr(thr, (duk_uint8_t *) &func, sizeof(func));
24395         duk_push_sprintf(thr, "_%04x_%04x",
24396                          (unsigned int) (duk_uint16_t) h->nargs,
24397                          (unsigned int) (duk_uint16_t) h->magic);
24398         duk_concat(thr, 3);
24399 }
24400 #endif
24401
24402 /*
24403  *  duk_tval slice copy
24404  */
24405
24406 DUK_INTERNAL void duk_copy_tvals_incref(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_size_t count) {
24407         duk_tval *tv;
24408
24409         DUK_ASSERT_API_ENTRY(thr);
24410         DUK_UNREF(thr);
24411         DUK_ASSERT(count * sizeof(duk_tval) >= count);  /* no wrap */
24412
24413         duk_memcpy_unsafe((void *) tv_dst, (const void *) tv_src, count * sizeof(duk_tval));
24414
24415         tv = tv_dst;
24416         while (count-- > 0) {
24417                 DUK_TVAL_INCREF(thr, tv);
24418                 tv++;
24419         }
24420 }
24421
24422 /* automatic undefs */
24423 #undef DUK__ASSERT_SPACE
24424 #undef DUK__CHECK_SPACE
24425 #undef DUK__ERROR_STASH_SHARED
24426 #undef DUK__PACK_ARGS
24427 #undef DUK__READABLE_ERRMSG_MAXCHARS
24428 #undef DUK__READABLE_STRING_MAXCHARS
24429 #undef DUK__READABLE_SUMMARY_MAXCHARS
24430 #line 1 "duk_api_string.c"
24431 /*
24432  *  String manipulation
24433  */
24434
24435 /* #include duk_internal.h -> already included */
24436
24437 DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) {
24438         duk_uint_t count;
24439         duk_uint_t i;
24440         duk_size_t idx;
24441         duk_size_t len;
24442         duk_hstring *h;
24443         duk_uint8_t *buf;
24444
24445         DUK_ASSERT_CTX_VALID(thr);
24446
24447         if (DUK_UNLIKELY(count_in <= 0)) {
24448                 if (count_in < 0) {
24449                         DUK_ERROR_RANGE_INVALID_COUNT(thr);
24450                         DUK_WO_NORETURN(return;);
24451                 }
24452                 DUK_ASSERT(count_in == 0);
24453                 duk_push_hstring_empty(thr);
24454                 return;
24455         }
24456         count = (duk_uint_t) count_in;
24457
24458         if (is_join) {
24459                 duk_size_t t1, t2, limit;
24460                 h = duk_to_hstring(thr, -((duk_idx_t) count) - 1);
24461                 DUK_ASSERT(h != NULL);
24462
24463                 /* A bit tricky overflow test, see doc/code-issues.rst. */
24464                 t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
24465                 t2 = (duk_size_t) (count - 1);
24466                 limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
24467                 if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
24468                         /* Combined size of separators already overflows. */
24469                         goto error_overflow;
24470                 }
24471                 len = (duk_size_t) (t1 * t2);
24472         } else {
24473                 len = (duk_size_t) 0;
24474         }
24475
24476         for (i = count; i >= 1; i--) {
24477                 duk_size_t new_len;
24478                 h = duk_to_hstring(thr, -((duk_idx_t) i));
24479                 new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
24480
24481                 /* Impose a string maximum length, need to handle overflow
24482                  * correctly.
24483                  */
24484                 if (new_len < len ||  /* wrapped */
24485                     new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) {
24486                         goto error_overflow;
24487                 }
24488                 len = new_len;
24489         }
24490
24491         DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
24492                              (unsigned long) count, (unsigned long) len));
24493
24494         /* Use stack allocated buffer to ensure reachability in errors
24495          * (e.g. intern error).
24496          */
24497         buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
24498         DUK_ASSERT(buf != NULL);
24499
24500         /* [ ... (sep) str1 str2 ... strN buf ] */
24501
24502         idx = 0;
24503         for (i = count; i >= 1; i--) {
24504                 if (is_join && i != count) {
24505                         h = duk_require_hstring(thr, -((duk_idx_t) count) - 2);  /* extra -1 for buffer */
24506                         duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
24507                         idx += DUK_HSTRING_GET_BYTELEN(h);
24508                 }
24509                 h = duk_require_hstring(thr, -((duk_idx_t) i) - 1);  /* extra -1 for buffer */
24510                 duk_memcpy(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
24511                 idx += DUK_HSTRING_GET_BYTELEN(h);
24512         }
24513
24514         DUK_ASSERT(idx == len);
24515
24516         /* [ ... (sep) str1 str2 ... strN buf ] */
24517
24518         /* Get rid of the strings early to minimize memory use before intern. */
24519
24520         if (is_join) {
24521                 duk_replace(thr, -((duk_idx_t) count) - 2);  /* overwrite sep */
24522                 duk_pop_n(thr, (duk_idx_t) count);
24523         } else {
24524                 duk_replace(thr, -((duk_idx_t) count) - 1);  /* overwrite str1 */
24525                 duk_pop_n(thr, (duk_idx_t) (count - 1));
24526         }
24527
24528         /* [ ... buf ] */
24529
24530         (void) duk_buffer_to_string(thr, -1);  /* Safe if inputs are safe. */
24531
24532         /* [ ... res ] */
24533         return;
24534
24535  error_overflow:
24536         DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
24537         DUK_WO_NORETURN(return;);
24538 }
24539
24540 DUK_EXTERNAL void duk_concat(duk_hthread *thr, duk_idx_t count) {
24541         DUK_ASSERT_API_ENTRY(thr);
24542
24543         duk__concat_and_join_helper(thr, count, 0 /*is_join*/);
24544 }
24545
24546 #if defined(DUK_USE_PREFER_SIZE)
24547 DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
24548         DUK_ASSERT_API_ENTRY(thr);
24549         duk_concat(thr, 2);
24550 }
24551 #else  /* DUK_USE_PREFER_SIZE */
24552 DUK_INTERNAL void duk_concat_2(duk_hthread *thr) {
24553         duk_hstring *h1;
24554         duk_hstring *h2;
24555         duk_uint8_t *buf;
24556         duk_size_t len1;
24557         duk_size_t len2;
24558         duk_size_t len;
24559
24560         DUK_ASSERT_API_ENTRY(thr);
24561         DUK_ASSERT(duk_get_top(thr) >= 2);  /* Trusted caller. */
24562
24563         h1 = duk_to_hstring(thr, -2);
24564         h2 = duk_to_hstring(thr, -1);
24565         len1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
24566         len2 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
24567         len = len1 + len2;
24568         if (DUK_UNLIKELY(len < len1 ||  /* wrapped */
24569                          len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN)) {
24570                 goto error_overflow;
24571         }
24572         buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, len);
24573         DUK_ASSERT(buf != NULL);
24574
24575         duk_memcpy((void *) buf, (const void *) DUK_HSTRING_GET_DATA(h1), (size_t) len1);
24576         duk_memcpy((void *) (buf + len1), (const void *) DUK_HSTRING_GET_DATA(h2), (size_t) len2);
24577         (void) duk_buffer_to_string(thr, -1);  /* Safe if inputs are safe. */
24578
24579         /* [ ... str1 str2 buf ] */
24580
24581         duk_replace(thr, -3);
24582         duk_pop_unsafe(thr);
24583         return;
24584
24585  error_overflow:
24586         DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
24587         DUK_WO_NORETURN(return;);
24588 }
24589 #endif  /* DUK_USE_PREFER_SIZE */
24590
24591 DUK_EXTERNAL void duk_join(duk_hthread *thr, duk_idx_t count) {
24592         DUK_ASSERT_API_ENTRY(thr);
24593
24594         duk__concat_and_join_helper(thr, count, 1 /*is_join*/);
24595 }
24596
24597 /* XXX: could map/decode be unified with duk_unicode_support.c code?
24598  * Case conversion needs also the character surroundings though.
24599  */
24600
24601 DUK_EXTERNAL void duk_decode_string(duk_hthread *thr, duk_idx_t idx, duk_decode_char_function callback, void *udata) {
24602         duk_hstring *h_input;
24603         const duk_uint8_t *p, *p_start, *p_end;
24604         duk_codepoint_t cp;
24605
24606         DUK_ASSERT_API_ENTRY(thr);
24607
24608         h_input = duk_require_hstring(thr, idx);  /* Accept symbols. */
24609         DUK_ASSERT(h_input != NULL);
24610
24611         p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
24612         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
24613         p = p_start;
24614
24615         for (;;) {
24616                 if (p >= p_end) {
24617                         break;
24618                 }
24619                 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
24620                 callback(udata, cp);
24621         }
24622 }
24623
24624 DUK_EXTERNAL void duk_map_string(duk_hthread *thr, duk_idx_t idx, duk_map_char_function callback, void *udata) {
24625         duk_hstring *h_input;
24626         duk_bufwriter_ctx bw_alloc;
24627         duk_bufwriter_ctx *bw;
24628         const duk_uint8_t *p, *p_start, *p_end;
24629         duk_codepoint_t cp;
24630
24631         DUK_ASSERT_API_ENTRY(thr);
24632
24633         idx = duk_normalize_index(thr, idx);
24634
24635         h_input = duk_require_hstring(thr, idx);  /* Accept symbols. */
24636         DUK_ASSERT(h_input != NULL);
24637
24638         bw = &bw_alloc;
24639         DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));  /* Reasonable output estimate. */
24640
24641         p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
24642         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
24643         p = p_start;
24644
24645         for (;;) {
24646                 /* XXX: could write output in chunks with fewer ensure calls,
24647                  * but relative benefit would be small here.
24648                  */
24649
24650                 if (p >= p_end) {
24651                         break;
24652                 }
24653                 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
24654                 cp = callback(udata, cp);
24655
24656                 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
24657         }
24658
24659         DUK_BW_COMPACT(thr, bw);
24660         (void) duk_buffer_to_string(thr, -1);  /* Safe, extended UTF-8 encoded. */
24661         duk_replace(thr, idx);
24662 }
24663
24664 DUK_EXTERNAL void duk_substring(duk_hthread *thr, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) {
24665         duk_hstring *h;
24666         duk_hstring *res;
24667         duk_size_t start_byte_offset;
24668         duk_size_t end_byte_offset;
24669         duk_size_t charlen;
24670
24671         DUK_ASSERT_API_ENTRY(thr);
24672
24673         idx = duk_require_normalize_index(thr, idx);  /* Accept symbols. */
24674         h = duk_require_hstring(thr, idx);
24675         DUK_ASSERT(h != NULL);
24676
24677         charlen = DUK_HSTRING_GET_CHARLEN(h);
24678         if (end_offset >= charlen) {
24679                 end_offset = charlen;
24680         }
24681         if (start_offset > end_offset) {
24682                 start_offset = end_offset;
24683         }
24684
24685         DUK_ASSERT_DISABLE(start_offset >= 0);
24686         DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h));
24687         DUK_ASSERT_DISABLE(end_offset >= 0);
24688         DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
24689
24690         /* Guaranteed by string limits. */
24691         DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
24692         DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
24693
24694         start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset);
24695         end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
24696
24697         DUK_ASSERT(end_byte_offset >= start_byte_offset);
24698         DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX);  /* Guaranteed by string limits. */
24699
24700         /* No size check is necessary. */
24701         res = duk_heap_strtable_intern_checked(thr,
24702                                                DUK_HSTRING_GET_DATA(h) + start_byte_offset,
24703                                                (duk_uint32_t) (end_byte_offset - start_byte_offset));
24704
24705         duk_push_hstring(thr, res);
24706         duk_replace(thr, idx);
24707 }
24708
24709 /* XXX: this is quite clunky.  Add Unicode helpers to scan backwards and
24710  * forwards with a callback to process codepoints?
24711  */
24712 DUK_EXTERNAL void duk_trim(duk_hthread *thr, duk_idx_t idx) {
24713         duk_hstring *h;
24714         const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2;  /* pointers for scanning */
24715         const duk_uint8_t *q_start, *q_end;  /* start (incl) and end (excl) of trimmed part */
24716         duk_codepoint_t cp;
24717
24718         DUK_ASSERT_API_ENTRY(thr);
24719
24720         idx = duk_require_normalize_index(thr, idx);  /* Accept symbols. */
24721         h = duk_require_hstring(thr, idx);
24722         DUK_ASSERT(h != NULL);
24723
24724         p_start = DUK_HSTRING_GET_DATA(h);
24725         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
24726
24727         p = p_start;
24728         while (p < p_end) {
24729                 p_tmp1 = p;
24730                 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end);
24731                 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
24732                         break;
24733                 }
24734                 p = p_tmp1;
24735         }
24736         q_start = p;
24737         if (p == p_end) {
24738                 /* Entire string is whitespace. */
24739                 q_end = p;
24740                 goto scan_done;
24741         }
24742
24743         p = p_end;
24744         while (p > p_start) {
24745                 p_tmp1 = p;
24746                 while (p > p_start) {
24747                         p--;
24748                         if (((*p) & 0xc0) != 0x80) {
24749                                 break;
24750                         }
24751                 }
24752                 p_tmp2 = p;
24753
24754                 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end);
24755                 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
24756                         p = p_tmp1;
24757                         break;
24758                 }
24759         }
24760         q_end = p;
24761
24762  scan_done:
24763         /* This may happen when forward and backward scanning disagree
24764          * (possible for non-extended-UTF-8 strings).
24765          */
24766         if (q_end < q_start) {
24767                 q_end = q_start;
24768         }
24769
24770         DUK_ASSERT(q_start >= p_start && q_start <= p_end);
24771         DUK_ASSERT(q_end >= p_start && q_end <= p_end);
24772         DUK_ASSERT(q_end >= q_start);
24773
24774         DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
24775                              (const void *) p_start, (const void *) p_end,
24776                              (const void *) q_start, (const void *) q_end));
24777
24778         if (q_start == p_start && q_end == p_end) {
24779                 DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)"));
24780                 return;
24781         }
24782
24783         duk_push_lstring(thr, (const char *) q_start, (duk_size_t) (q_end - q_start));
24784         duk_replace(thr, idx);
24785 }
24786
24787 DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_hthread *thr, duk_idx_t idx, duk_size_t char_offset) {
24788         duk_hstring *h;
24789         duk_ucodepoint_t cp;
24790
24791         DUK_ASSERT_API_ENTRY(thr);
24792
24793         /* XXX: Share code with String.prototype.charCodeAt?  Main difference
24794          * is handling of clamped offsets.
24795          */
24796
24797         h = duk_require_hstring(thr, idx);  /* Accept symbols. */
24798         DUK_ASSERT(h != NULL);
24799
24800         DUK_ASSERT_DISABLE(char_offset >= 0);  /* Always true, arg is unsigned. */
24801         if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
24802                 return 0;
24803         }
24804
24805         DUK_ASSERT(char_offset <= DUK_UINT_MAX);  /* Guaranteed by string limits. */
24806         cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/);
24807         return (duk_codepoint_t) cp;
24808 }
24809 #line 1 "duk_api_time.c"
24810 /*
24811  *  Date/time.
24812  */
24813
24814 /* #include duk_internal.h -> already included */
24815
24816 DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time(duk_hthread *thr) {
24817         /* ECMAScript time, with millisecond fractions.  Exposed via
24818          * duk_get_now() for example.
24819          */
24820         DUK_UNREF(thr);
24821         return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
24822 }
24823
24824 DUK_INTERNAL duk_double_t duk_time_get_ecmascript_time_nofrac(duk_hthread *thr) {
24825         /* ECMAScript time without millisecond fractions.  Exposed via
24826          * the Date built-in which doesn't allow fractions.
24827          */
24828         DUK_UNREF(thr);
24829         return (duk_double_t) DUK_FLOOR(DUK_USE_DATE_GET_NOW(thr));
24830 }
24831
24832 DUK_INTERNAL duk_double_t duk_time_get_monotonic_time(duk_hthread *thr) {
24833         DUK_UNREF(thr);
24834 #if defined(DUK_USE_GET_MONOTONIC_TIME)
24835         return (duk_double_t) DUK_USE_GET_MONOTONIC_TIME(thr);
24836 #else
24837         return (duk_double_t) DUK_USE_DATE_GET_NOW(thr);
24838 #endif
24839 }
24840
24841 DUK_EXTERNAL duk_double_t duk_get_now(duk_hthread *thr) {
24842         DUK_ASSERT_API_ENTRY(thr);
24843         DUK_UNREF(thr);
24844
24845         /* This API intentionally allows millisecond fractions. */
24846         return duk_time_get_ecmascript_time(thr);
24847 }
24848
24849 #if 0  /* XXX: worth exposing? */
24850 DUK_EXTERNAL duk_double_t duk_get_monotonic_time(duk_hthread *thr) {
24851         DUK_ASSERT_API_ENTRY(thr);
24852         DUK_UNREF(thr);
24853
24854         return duk_time_get_monotonic_time(thr);
24855 }
24856 #endif
24857
24858 DUK_EXTERNAL void duk_time_to_components(duk_hthread *thr, duk_double_t timeval, duk_time_components *comp) {
24859         duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
24860         duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
24861         duk_uint_t flags;
24862
24863         DUK_ASSERT_API_ENTRY(thr);
24864         DUK_ASSERT(comp != NULL);  /* XXX: or check? */
24865         DUK_UNREF(thr);
24866
24867         /* Convert as one-based, but change month to zero-based to match the
24868          * ECMAScript Date built-in behavior 1:1.
24869          */
24870         flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO;
24871
24872         duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags);
24873
24874         /* XXX: sub-millisecond accuracy for the API */
24875
24876         DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0);
24877         comp->year = dparts[DUK_DATE_IDX_YEAR];
24878         comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0;
24879         comp->day = dparts[DUK_DATE_IDX_DAY];
24880         comp->hours = dparts[DUK_DATE_IDX_HOUR];
24881         comp->minutes = dparts[DUK_DATE_IDX_MINUTE];
24882         comp->seconds = dparts[DUK_DATE_IDX_SECOND];
24883         comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND];
24884         comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY];
24885 }
24886
24887 DUK_EXTERNAL duk_double_t duk_components_to_time(duk_hthread *thr, duk_time_components *comp) {
24888         duk_double_t d;
24889         duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
24890         duk_uint_t flags;
24891
24892         DUK_ASSERT_API_ENTRY(thr);
24893         DUK_ASSERT(comp != NULL);  /* XXX: or check? */
24894         DUK_UNREF(thr);
24895
24896         /* Match Date constructor behavior (with UTC time).  Month is given
24897          * as zero-based.  Day-of-month is given as one-based so normalize
24898          * it to zero-based as the internal conversion helpers expects all
24899          * components to be zero-based.
24900          */
24901         flags = 0;
24902
24903         /* XXX: expensive conversion; use array format in API instead, or unify
24904          * time provider and time API to use same struct?
24905          */
24906
24907         dparts[DUK_DATE_IDX_YEAR] = comp->year;
24908         dparts[DUK_DATE_IDX_MONTH] = comp->month;
24909         dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0;
24910         dparts[DUK_DATE_IDX_HOUR] = comp->hours;
24911         dparts[DUK_DATE_IDX_MINUTE] = comp->minutes;
24912         dparts[DUK_DATE_IDX_SECOND] = comp->seconds;
24913         dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds;
24914         dparts[DUK_DATE_IDX_WEEKDAY] = 0;  /* ignored */
24915
24916         d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
24917
24918         return d;
24919 }
24920 #line 1 "duk_bi_array.c"
24921 /*
24922  *  Array built-ins
24923  *
24924  *  Most Array built-ins are intentionally generic in ECMAScript, and are
24925  *  intended to work even when the 'this' binding is not an Array instance.
24926  *  This ECMAScript feature is also used by much real world code.  For this
24927  *  reason the implementations here don't assume exotic Array behavior or
24928  *  e.g. presence of a .length property.  However, some algorithms have a
24929  *  fast path for duk_harray backed actual Array instances, enabled when
24930  *  footprint is not a concern.
24931  *
24932  *  XXX: the "Throw" flag should be set for (almost?) all [[Put]] and
24933  *  [[Delete]] operations, but it's currently false throughout.  Go through
24934  *  all put/delete cases and check throw flag use.  Need a new API primitive
24935  *  which allows throws flag to be specified.
24936  *
24937  *  XXX: array lengths above 2G won't work reliably.  There are many places
24938  *  where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff],
24939  *  i.e. -33- bits).  Although array 'length' cannot be written to be outside
24940  *  the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so)
24941  *  some intermediate values may be above 0xffffffff and this may not be always
24942  *  correctly handled now (duk_uint32_t is not enough for all algorithms).
24943  *  For instance, push() can legitimately write entries beyond length 0xffffffff
24944  *  and cause a RangeError only at the end.  To do this properly, the current
24945  *  push() implementation tracks the array index using a 'double' instead of a
24946  *  duk_uint32_t (which is somewhat awkward).  See test-bi-array-push-maxlen.js.
24947  *
24948  *  On using "put" vs. "def" prop
24949  *  =============================
24950  *
24951  *  Code below must be careful to use the appropriate primitive as it matters
24952  *  for compliance.  When using "put" there may be inherited properties in
24953  *  Array.prototype which cause side effects when values are written.  When
24954  *  using "define" there are no such side effects, and many test262 test cases
24955  *  check for this (for real world code, such side effects are very rare).
24956  *  Both "put" and "define" are used in the E5.1 specification; as a rule,
24957  *  "put" is used when modifying an existing array (or a non-array 'this'
24958  *  binding) and "define" for setting values into a fresh result array.
24959  */
24960
24961 /* #include duk_internal.h -> already included */
24962
24963 /* Perform an intermediate join when this many elements have been pushed
24964  * on the value stack.
24965  */
24966 #define  DUK__ARRAY_MID_JOIN_LIMIT  4096
24967
24968 #if defined(DUK_USE_ARRAY_BUILTIN)
24969
24970 /*
24971  *  Shared helpers.
24972  */
24973
24974 /* Shared entry code for many Array built-ins: the 'this' binding is pushed
24975  * on the value stack and object coerced, and the current .length is returned.
24976  * Note that length is left on stack (it could be popped, but that's not
24977  * usually necessary because call handling will clean it up automatically).
24978  */
24979 DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_hthread *thr) {
24980         duk_uint32_t len;
24981
24982         /* XXX: push more directly? */
24983         (void) duk_push_this_coercible_to_object(thr);
24984         DUK_ASSERT_HOBJECT_VALID(duk_get_hobject(thr, -1));
24985         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_LENGTH);
24986         len = duk_to_uint32(thr, -1);
24987
24988         /* -> [ ... ToObject(this) ToUint32(length) ] */
24989         return len;
24990 }
24991
24992 DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_hthread *thr) {
24993         /* Range limited to [0, 0x7fffffff] range, i.e. range that can be
24994          * represented with duk_int32_t.  Use this when the method doesn't
24995          * handle the full 32-bit unsigned range correctly.
24996          */
24997         duk_uint32_t ret = duk__push_this_obj_len_u32(thr);
24998         if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
24999                 DUK_ERROR_RANGE_INVALID_LENGTH(thr);
25000                 DUK_WO_NORETURN(return 0U;);
25001         }
25002         return ret;
25003 }
25004
25005 #if defined(DUK_USE_ARRAY_FASTPATH)
25006 /* Check if 'this' binding is an Array instance (duk_harray) which satisfies
25007  * a few other guarantees for fast path operation.  The fast path doesn't
25008  * need to handle all operations, even for duk_harrays, but must handle a
25009  * significant fraction to improve performance.  Return a non-NULL duk_harray
25010  * pointer when all fast path criteria are met, NULL otherwise.
25011  */
25012 DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_hthread *thr) {
25013         duk_tval *tv;
25014         duk_hobject *h;
25015         duk_uint_t flags_mask, flags_bits, flags_value;
25016
25017         DUK_ASSERT(thr->valstack_bottom > thr->valstack);  /* because call in progress */
25018         tv = DUK_GET_THIS_TVAL_PTR(thr);
25019
25020         /* Fast path requires that 'this' is a duk_harray.  Read only arrays
25021          * (ROM backed) are also rejected for simplicity.
25022          */
25023         if (!DUK_TVAL_IS_OBJECT(tv)) {
25024                 DUK_DD(DUK_DDPRINT("reject array fast path: not an object"));
25025                 return NULL;
25026         }
25027         h = DUK_TVAL_GET_OBJECT(tv);
25028         DUK_ASSERT(h != NULL);
25029         flags_mask = DUK_HOBJECT_FLAG_ARRAY_PART | \
25030                      DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
25031                      DUK_HEAPHDR_FLAG_READONLY;
25032         flags_bits = DUK_HOBJECT_FLAG_ARRAY_PART | \
25033                      DUK_HOBJECT_FLAG_EXOTIC_ARRAY;
25034         flags_value = DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) h);
25035         if ((flags_value & flags_mask) != flags_bits) {
25036                 DUK_DD(DUK_DDPRINT("reject array fast path: object flag check failed"));
25037                 return NULL;
25038         }
25039
25040         /* In some cases a duk_harray's 'length' may be larger than the
25041          * current array part allocation.  Avoid the fast path in these
25042          * cases, so that all fast path code can safely assume that all
25043          * items in the range [0,length[ are backed by the current array
25044          * part allocation.
25045          */
25046         if (((duk_harray *) h)->length > DUK_HOBJECT_GET_ASIZE(h)) {
25047                 DUK_DD(DUK_DDPRINT("reject array fast path: length > array part size"));
25048                 return NULL;
25049         }
25050
25051         /* Guarantees for fast path. */
25052         DUK_ASSERT(h != NULL);
25053         DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, h) != NULL);
25054         DUK_ASSERT(((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h));
25055
25056         DUK_DD(DUK_DDPRINT("array fast path allowed for: %!O", (duk_heaphdr *) h));
25057         return (duk_harray *) h;
25058 }
25059 #endif  /* DUK_USE_ARRAY_FASTPATH */
25060
25061 /*
25062  *  Constructor
25063  */
25064
25065 DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_hthread *thr) {
25066         duk_idx_t nargs;
25067         duk_harray *a;
25068         duk_double_t d;
25069         duk_uint32_t len;
25070         duk_uint32_t len_prealloc;
25071
25072         nargs = duk_get_top(thr);
25073
25074         if (nargs == 1 && duk_is_number(thr, 0)) {
25075                 /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
25076                 d = duk_get_number(thr, 0);
25077                 len = duk_to_uint32(thr, 0);
25078                 if (((duk_double_t) len) != d) {
25079                         DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
25080                 }
25081
25082                 /* For small lengths create a dense preallocated array.
25083                  * For large arrays preallocate an initial part.
25084                  */
25085                 len_prealloc = len < 64 ? len : 64;
25086                 a = duk_push_harray_with_size(thr, len_prealloc);
25087                 DUK_ASSERT(a != NULL);
25088                 a->length = len;
25089                 return 1;
25090         }
25091
25092         duk_pack(thr, nargs);
25093         return 1;
25094 }
25095
25096 /*
25097  *  isArray()
25098  */
25099
25100 DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_hthread *thr) {
25101         duk_hobject *h;
25102
25103         h = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_ARRAY);
25104         duk_push_boolean(thr, (h != NULL));
25105         return 1;
25106 }
25107
25108 /*
25109  *  toString()
25110  */
25111
25112 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_hthread *thr) {
25113         (void) duk_push_this_coercible_to_object(thr);
25114         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_JOIN);
25115
25116         /* [ ... this func ] */
25117         if (!duk_is_callable(thr, -1)) {
25118                 /* Fall back to the initial (original) Object.toString().  We don't
25119                  * currently have pointers to the built-in functions, only the top
25120                  * level global objects (like "Array") so this is now done in a bit
25121                  * of a hacky manner.  It would be cleaner to push the (original)
25122                  * function and use duk_call_method().
25123                  */
25124
25125                 /* XXX: 'this' will be ToObject() coerced twice, which is incorrect
25126                  * but should have no visible side effects.
25127                  */
25128                 DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
25129                 duk_set_top(thr, 0);
25130                 return duk_bi_object_prototype_to_string(thr);  /* has access to 'this' binding */
25131         }
25132
25133         /* [ ... this func ] */
25134
25135         duk_insert(thr, -2);
25136
25137         /* [ ... func this ] */
25138
25139         DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
25140                              (duk_tval *) duk_get_tval(thr, -2),
25141                              (duk_tval *) duk_get_tval(thr, -1)));
25142         duk_call_method(thr, 0);
25143
25144         return 1;
25145 }
25146
25147 /*
25148  *  concat()
25149  */
25150
25151 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_hthread *thr) {
25152         duk_idx_t i, n;
25153         duk_uint32_t j, idx, len;
25154         duk_hobject *h;
25155         duk_size_t tmp_len;
25156
25157         /* XXX: In ES2015 Array .length can be up to 2^53-1.  The current
25158          * implementation is limited to 2^32-1.
25159          */
25160
25161         /* XXX: Fast path for array 'this' and array element. */
25162
25163         /* XXX: The insert here is a bit expensive if there are a lot of items.
25164          * It could also be special cased in the outermost for loop quite easily
25165          * (as the element is dup()'d anyway).
25166          */
25167
25168         (void) duk_push_this_coercible_to_object(thr);
25169         duk_insert(thr, 0);
25170         n = duk_get_top(thr);
25171         duk_push_array(thr);  /* -> [ ToObject(this) item1 ... itemN arr ] */
25172
25173         /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
25174          * (which differs from the official algorithm).  If no error is thrown, this
25175          * doesn't matter as the length is updated at the end.  However, if an error
25176          * is thrown, the length will be unset.  That shouldn't matter because the
25177          * caller won't get a reference to the intermediate value.
25178          */
25179
25180         idx = 0;
25181         for (i = 0; i < n; i++) {
25182                 duk_bool_t spreadable;
25183                 duk_bool_t need_has_check;
25184
25185                 DUK_ASSERT_TOP(thr, n + 1);
25186
25187                 /* [ ToObject(this) item1 ... itemN arr ] */
25188
25189                 h = duk_get_hobject(thr, i);
25190
25191                 if (h == NULL) {
25192                         spreadable = 0;
25193                 } else {
25194 #if defined(DUK_USE_SYMBOL_BUILTIN)
25195                         duk_get_prop_stridx(thr, i, DUK_STRIDX_WELLKNOWN_SYMBOL_IS_CONCAT_SPREADABLE);
25196                         if (duk_is_undefined(thr, -1)) {
25197                                 spreadable = (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY);
25198                         } else {
25199                                 spreadable = duk_to_boolean(thr, -1);
25200                         }
25201                         duk_pop_nodecref_unsafe(thr);
25202 #else
25203                         spreadable = (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY);
25204 #endif
25205                 }
25206
25207                 if (!spreadable) {
25208                         duk_dup(thr, i);
25209                         duk_xdef_prop_index_wec(thr, -2, idx);
25210                         idx++;
25211                         if (DUK_UNLIKELY(idx == 0U)) {
25212                                 /* Index after update is 0, and index written
25213                                  * was 0xffffffffUL which is no longer a valid
25214                                  * array index.
25215                                  */
25216                                 goto fail_wrap;
25217                         }
25218                         continue;
25219                 }
25220
25221                 DUK_ASSERT(duk_is_object(thr, i));
25222                 need_has_check = (DUK_HOBJECT_IS_PROXY(h) != 0);  /* Always 0 w/o Proxy support. */
25223
25224                 /* [ ToObject(this) item1 ... itemN arr ] */
25225
25226                 tmp_len = duk_get_length(thr, i);
25227                 len = (duk_uint32_t) tmp_len;
25228                 if (DUK_UNLIKELY(tmp_len != (duk_size_t) len)) {
25229                         goto fail_wrap;
25230                 }
25231                 if (DUK_UNLIKELY(idx + len < idx)) {
25232                         /* Result length must be at most 0xffffffffUL to be
25233                          * a valid 32-bit array index.
25234                          */
25235                         goto fail_wrap;
25236                 }
25237                 for (j = 0; j < len; j++) {
25238                         /* For a Proxy element, an explicit 'has' check is
25239                          * needed to allow the Proxy to present gaps.
25240                          */
25241                         if (need_has_check) {
25242                                 if (duk_has_prop_index(thr, i, j)) {
25243                                         duk_get_prop_index(thr, i, j);
25244                                         duk_xdef_prop_index_wec(thr, -2, idx);
25245                                 }
25246                         } else {
25247                                 if (duk_get_prop_index(thr, i, j)) {
25248                                         duk_xdef_prop_index_wec(thr, -2, idx);
25249                                 } else {
25250                                         duk_pop_undefined(thr);
25251                                 }
25252                         }
25253                         idx++;
25254                         DUK_ASSERT(idx != 0U);  /* Wrap check above. */
25255                 }
25256         }
25257
25258         /* ES5.1 has a specification "bug" in that nonexistent trailing
25259          * elements don't affect the result .length.  Test262 and other
25260          * engines disagree, and the specification bug was fixed in ES2015
25261          * (see NOTE 1 in https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.concat).
25262          */
25263         duk_push_uarridx(thr, idx);
25264         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
25265
25266         DUK_ASSERT_TOP(thr, n + 1);
25267         return 1;
25268
25269  fail_wrap:
25270         DUK_ERROR_RANGE_INVALID_LENGTH(thr);
25271         DUK_WO_NORETURN(return 0;);
25272 }
25273
25274 /*
25275  *  join(), toLocaleString()
25276  *
25277  *  Note: checking valstack is necessary, but only in the per-element loop.
25278  *
25279  *  Note: the trivial approach of pushing all the elements on the value stack
25280  *  and then calling duk_join() fails when the array contains a large number
25281  *  of elements.  This problem can't be offloaded to duk_join() because the
25282  *  elements to join must be handled here and have special handling.  Current
25283  *  approach is to do intermediate joins with very large number of elements.
25284  *  There is no fancy handling; the prefix gets re-joined multiple times.
25285  */
25286
25287 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_hthread *thr) {
25288         duk_uint32_t len, count;
25289         duk_uint32_t idx;
25290         duk_small_int_t to_locale_string = duk_get_current_magic(thr);
25291         duk_idx_t valstack_required;
25292
25293         /* For join(), nargs is 1.  For toLocaleString(), nargs is 0 and
25294          * setting the top essentially pushes an undefined to the stack,
25295          * thus defaulting to a comma separator.
25296          */
25297         duk_set_top(thr, 1);
25298         if (duk_is_undefined(thr, 0)) {
25299                 duk_pop_undefined(thr);
25300                 duk_push_hstring_stridx(thr, DUK_STRIDX_COMMA);
25301         } else {
25302                 duk_to_string(thr, 0);
25303         }
25304
25305         len = duk__push_this_obj_len_u32(thr);
25306
25307         /* [ sep ToObject(this) len ] */
25308
25309         DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
25310                              (duk_tval *) duk_get_tval(thr, 0),
25311                              (duk_tval *) duk_get_tval(thr, 1),
25312                              (unsigned long) len));
25313
25314         /* The extra (+4) is tight. */
25315         valstack_required = (duk_idx_t) ((len >= DUK__ARRAY_MID_JOIN_LIMIT ?
25316                                           DUK__ARRAY_MID_JOIN_LIMIT : len) + 4);
25317         duk_require_stack(thr, valstack_required);
25318
25319         duk_dup_0(thr);
25320
25321         /* [ sep ToObject(this) len sep ] */
25322
25323         count = 0;
25324         idx = 0;
25325         for (;;) {
25326                 DUK_DDD(DUK_DDDPRINT("join idx=%ld", (long) idx));
25327                 if (count >= DUK__ARRAY_MID_JOIN_LIMIT ||   /* intermediate join to avoid valstack overflow */
25328                     idx >= len) { /* end of loop (careful with len==0) */
25329                         /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
25330                         DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
25331                                              (long) count, (long) idx, (long) len));
25332                         duk_join(thr, (duk_idx_t) count);  /* -> [ sep ToObject(this) len str ] */
25333                         duk_dup_0(thr);                    /* -> [ sep ToObject(this) len str sep ] */
25334                         duk_insert(thr, -2);               /* -> [ sep ToObject(this) len sep str ] */
25335                         count = 1;
25336                 }
25337                 if (idx >= len) {
25338                         /* if true, the stack already contains the final result */
25339                         break;
25340                 }
25341
25342                 duk_get_prop_index(thr, 1, (duk_uarridx_t) idx);
25343                 if (duk_is_null_or_undefined(thr, -1)) {
25344                         duk_pop_nodecref_unsafe(thr);
25345                         duk_push_hstring_empty(thr);
25346                 } else {
25347                         if (to_locale_string) {
25348                                 duk_to_object(thr, -1);
25349                                 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_LOCALE_STRING);
25350                                 duk_insert(thr, -2);  /* -> [ ... toLocaleString ToObject(val) ] */
25351                                 duk_call_method(thr, 0);
25352                         }
25353                         duk_to_string(thr, -1);
25354                 }
25355
25356                 count++;
25357                 idx++;
25358         }
25359
25360         /* [ sep ToObject(this) len sep result ] */
25361
25362         return 1;
25363 }
25364
25365 /*
25366  *  pop(), push()
25367  */
25368
25369 #if defined(DUK_USE_ARRAY_FASTPATH)
25370 DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_hthread *thr, duk_harray *h_arr) {
25371         duk_tval *tv_arraypart;
25372         duk_tval *tv_val;
25373         duk_uint32_t len;
25374
25375         tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
25376         len = h_arr->length;
25377         if (len <= 0) {
25378                 /* nop, return undefined */
25379                 return 0;
25380         }
25381
25382         len--;
25383         h_arr->length = len;
25384
25385         /* Fast path doesn't check for an index property inherited from
25386          * Array.prototype.  This is quite often acceptable; if not,
25387          * disable fast path.
25388          */
25389         DUK_ASSERT_VS_SPACE(thr);
25390         tv_val = tv_arraypart + len;
25391         if (DUK_TVAL_IS_UNUSED(tv_val)) {
25392                 /* No net refcount change.  Value stack already has
25393                  * 'undefined' based on value stack init policy.
25394                  */
25395                 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
25396                 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv_val));
25397         } else {
25398                 /* No net refcount change. */
25399                 DUK_TVAL_SET_TVAL(thr->valstack_top, tv_val);
25400                 DUK_TVAL_SET_UNUSED(tv_val);
25401         }
25402         thr->valstack_top++;
25403
25404         /* XXX: there's no shrink check in the fast path now */
25405
25406         return 1;
25407 }
25408 #endif  /* DUK_USE_ARRAY_FASTPATH */
25409
25410 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_hthread *thr) {
25411         duk_uint32_t len;
25412         duk_uint32_t idx;
25413 #if defined(DUK_USE_ARRAY_FASTPATH)
25414         duk_harray *h_arr;
25415 #endif
25416
25417         DUK_ASSERT_TOP(thr, 0);
25418
25419 #if defined(DUK_USE_ARRAY_FASTPATH)
25420         h_arr = duk__arraypart_fastpath_this(thr);
25421         if (h_arr) {
25422                 return duk__array_pop_fastpath(thr, h_arr);
25423         }
25424 #endif
25425
25426         /* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */
25427
25428         len = duk__push_this_obj_len_u32(thr);
25429         if (len == 0) {
25430                 duk_push_int(thr, 0);
25431                 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
25432                 return 0;
25433         }
25434         idx = len - 1;
25435
25436         duk_get_prop_index(thr, 0, (duk_uarridx_t) idx);
25437         duk_del_prop_index(thr, 0, (duk_uarridx_t) idx);
25438         duk_push_u32(thr, idx);
25439         duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
25440         return 1;
25441 }
25442
25443 #if defined(DUK_USE_ARRAY_FASTPATH)
25444 DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_hthread *thr, duk_harray *h_arr) {
25445         duk_tval *tv_arraypart;
25446         duk_tval *tv_src;
25447         duk_tval *tv_dst;
25448         duk_uint32_t len;
25449         duk_idx_t i, n;
25450
25451         len = h_arr->length;
25452         tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
25453
25454         n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
25455         DUK_ASSERT(n >= 0);
25456         DUK_ASSERT((duk_uint32_t) n <= DUK_UINT32_MAX);
25457         if (DUK_UNLIKELY(len + (duk_uint32_t) n < len)) {
25458                 DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
25459                 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);  /* != 0 return value returned as is by caller */
25460         }
25461         if (len + (duk_uint32_t) n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) {
25462                 /* Array part would need to be extended.  Rely on slow path
25463                  * for now.
25464                  *
25465                  * XXX: Rework hobject code a bit and add extend support.
25466                  */
25467                 return 0;
25468         }
25469
25470         tv_src = thr->valstack_bottom;
25471         tv_dst = tv_arraypart + len;
25472         for (i = 0; i < n; i++) {
25473                 /* No net refcount change; reset value stack values to
25474                  * undefined to satisfy value stack init policy.
25475                  */
25476                 DUK_TVAL_SET_TVAL(tv_dst, tv_src);
25477                 DUK_TVAL_SET_UNDEFINED(tv_src);
25478                 tv_src++;
25479                 tv_dst++;
25480         }
25481         thr->valstack_top = thr->valstack_bottom;
25482         len += (duk_uint32_t) n;
25483         h_arr->length = len;
25484
25485         DUK_ASSERT((duk_uint_t) len == len);
25486         duk_push_uint(thr, (duk_uint_t) len);
25487         return 1;
25488 }
25489 #endif  /* DUK_USE_ARRAY_FASTPATH */
25490
25491 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_hthread *thr) {
25492         /* Note: 'this' is not necessarily an Array object.  The push()
25493          * algorithm is supposed to work for other kinds of objects too,
25494          * so the algorithm has e.g. an explicit update for the 'length'
25495          * property which is normally "magical" in arrays.
25496          */
25497
25498         duk_uint32_t len;
25499         duk_idx_t i, n;
25500 #if defined(DUK_USE_ARRAY_FASTPATH)
25501         duk_harray *h_arr;
25502 #endif
25503
25504 #if defined(DUK_USE_ARRAY_FASTPATH)
25505         h_arr = duk__arraypart_fastpath_this(thr);
25506         if (h_arr) {
25507                 duk_ret_t rc;
25508                 rc = duk__array_push_fastpath(thr, h_arr);
25509                 if (rc != 0) {
25510                         return rc;
25511                 }
25512                 DUK_DD(DUK_DDPRINT("array push() fast path exited, resize case"));
25513         }
25514 #endif
25515
25516         n = duk_get_top(thr);
25517         len = duk__push_this_obj_len_u32(thr);
25518
25519         /* [ arg1 ... argN obj length ] */
25520
25521         /* Technically Array.prototype.push() can create an Array with length
25522          * longer than 2^32-1, i.e. outside the 32-bit range.  The final length
25523          * is *not* wrapped to 32 bits in the specification.
25524          *
25525          * This implementation tracks length with a uint32 because it's much
25526          * more practical.
25527          *
25528          * See: test-bi-array-push-maxlen.js.
25529          */
25530
25531         if (len + (duk_uint32_t) n < len) {
25532                 DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
25533                 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
25534         }
25535
25536         for (i = 0; i < n; i++) {
25537                 duk_dup(thr, i);
25538                 duk_put_prop_index(thr, -3, (duk_uarridx_t) (len + (duk_uint32_t) i));
25539         }
25540         len += (duk_uint32_t) n;
25541
25542         duk_push_u32(thr, len);
25543         duk_dup_top(thr);
25544         duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
25545
25546         /* [ arg1 ... argN obj length new_length ] */
25547         return 1;
25548 }
25549
25550 /*
25551  *  sort()
25552  *
25553  *  Currently qsort with random pivot.  This is now really, really slow,
25554  *  because there is no fast path for array parts.
25555  *
25556  *  Signed indices are used because qsort() leaves and degenerate cases
25557  *  may use a negative offset.
25558  */
25559
25560 DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_hthread *thr, duk_int_t idx1, duk_int_t idx2) {
25561         duk_bool_t have1, have2;
25562         duk_bool_t undef1, undef2;
25563         duk_small_int_t ret;
25564         duk_idx_t idx_obj = 1;  /* fixed offsets in valstack */
25565         duk_idx_t idx_fn = 0;
25566         duk_hstring *h1, *h2;
25567
25568         /* Fast exit if indices are identical.  This is valid for a non-existent property,
25569          * for an undefined value, and almost always for ToString() coerced comparison of
25570          * arbitrary values (corner cases where this is not the case include e.g. a an
25571          * object with varying ToString() coercion).
25572          *
25573          * The specification does not prohibit "caching" of values read from the array, so
25574          * assuming equality for comparing an index with itself falls into the category of
25575          * "caching".
25576          *
25577          * Also, compareFn may be inconsistent, so skipping a call to compareFn here may
25578          * have an effect on the final result.  The specification does not require any
25579          * specific behavior for inconsistent compare functions, so again, this fast path
25580          * is OK.
25581          */
25582
25583         if (idx1 == idx2) {
25584                 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit",
25585                                      (long) idx1, (long) idx2));
25586                 return 0;
25587         }
25588
25589         have1 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx1);
25590         have2 = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) idx2);
25591
25592         DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
25593                              (long) idx1, (long) idx2, (long) have1, (long) have2,
25594                              (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
25595
25596         if (have1) {
25597                 if (have2) {
25598                         ;
25599                 } else {
25600                         ret = -1;
25601                         goto pop_ret;
25602                 }
25603         } else {
25604                 if (have2) {
25605                         ret = 1;
25606                         goto pop_ret;
25607                 } else {
25608                         ret = 0;
25609                         goto pop_ret;
25610                 }
25611         }
25612
25613         undef1 = duk_is_undefined(thr, -2);
25614         undef2 = duk_is_undefined(thr, -1);
25615         if (undef1) {
25616                 if (undef2) {
25617                         ret = 0;
25618                         goto pop_ret;
25619                 } else {
25620                         ret = 1;
25621                         goto pop_ret;
25622                 }
25623         } else {
25624                 if (undef2) {
25625                         ret = -1;
25626                         goto pop_ret;
25627                 } else {
25628                         ;
25629                 }
25630         }
25631
25632         if (!duk_is_undefined(thr, idx_fn)) {
25633                 duk_double_t d;
25634
25635                 /* No need to check callable; duk_call() will do that. */
25636                 duk_dup(thr, idx_fn);    /* -> [ ... x y fn ] */
25637                 duk_insert(thr, -3);     /* -> [ ... fn x y ] */
25638                 duk_call(thr, 2);        /* -> [ ... res ] */
25639
25640                 /* ES5 is a bit vague about what to do if the return value is
25641                  * not a number.  ES2015 provides a concrete description:
25642                  * http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare.
25643                  */
25644
25645                 d = duk_to_number_m1(thr);
25646                 if (d < 0.0) {
25647                         ret = -1;
25648                 } else if (d > 0.0) {
25649                         ret = 1;
25650                 } else {
25651                         /* Because NaN compares to false, NaN is handled here
25652                          * without an explicit check above.
25653                          */
25654                         ret = 0;
25655                 }
25656
25657                 duk_pop_nodecref_unsafe(thr);
25658                 DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
25659                 return ret;
25660         }
25661
25662         /* string compare is the default (a bit oddly) */
25663
25664         /* XXX: any special handling for plain array; causes repeated coercion now? */
25665         h1 = duk_to_hstring(thr, -2);
25666         h2 = duk_to_hstring_m1(thr);
25667         DUK_ASSERT(h1 != NULL);
25668         DUK_ASSERT(h2 != NULL);
25669
25670         ret = duk_js_string_compare(h1, h2);  /* retval is directly usable */
25671         goto pop_ret;
25672
25673  pop_ret:
25674         duk_pop_2_unsafe(thr);
25675         DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
25676         return ret;
25677 }
25678
25679 DUK_LOCAL void duk__array_sort_swap(duk_hthread *thr, duk_int_t l, duk_int_t r) {
25680         duk_bool_t have_l, have_r;
25681         duk_idx_t idx_obj = 1;  /* fixed offset in valstack */
25682
25683         if (l == r) {
25684                 return;
25685         }
25686
25687         /* swap elements; deal with non-existent elements correctly */
25688         have_l = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) l);
25689         have_r = duk_get_prop_index(thr, idx_obj, (duk_uarridx_t) r);
25690
25691         if (have_r) {
25692                 /* right exists, [[Put]] regardless whether or not left exists */
25693                 duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) l);
25694         } else {
25695                 duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) l);
25696                 duk_pop_undefined(thr);
25697         }
25698
25699         if (have_l) {
25700                 duk_put_prop_index(thr, idx_obj, (duk_uarridx_t) r);
25701         } else {
25702                 duk_del_prop_index(thr, idx_obj, (duk_uarridx_t) r);
25703                 duk_pop_undefined(thr);
25704         }
25705 }
25706
25707 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
25708 /* Debug print which visualizes the qsort partitioning process. */
25709 DUK_LOCAL void duk__debuglog_qsort_state(duk_hthread *thr, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
25710         char buf[4096];
25711         char *ptr = buf;
25712         duk_int_t i, n;
25713         n = (duk_int_t) duk_get_length(thr, 1);
25714         if (n > 4000) {
25715                 n = 4000;
25716         }
25717         *ptr++ = '[';
25718         for (i = 0; i < n; i++) {
25719                 if (i == pivot) {
25720                         *ptr++ = '|';
25721                 } else if (i == lo) {
25722                         *ptr++ = '<';
25723                 } else if (i == hi) {
25724                         *ptr++ = '>';
25725                 } else if (i >= lo && i <= hi) {
25726                         *ptr++ = '-';
25727                 } else {
25728                         *ptr++ = ' ';
25729                 }
25730         }
25731         *ptr++ = ']';
25732         *ptr++ = '\0';
25733
25734         DUK_DDD(DUK_DDDPRINT("%s   (lo=%ld, hi=%ld, pivot=%ld)",
25735                              (const char *) buf, (long) lo, (long) hi, (long) pivot));
25736 }
25737 #endif
25738
25739 DUK_LOCAL void duk__array_qsort(duk_hthread *thr, duk_int_t lo, duk_int_t hi) {
25740         duk_int_t p, l, r;
25741
25742         /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
25743
25744         DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
25745                              (long) lo, (long) hi, (duk_tval *) duk_get_tval(thr, 1)));
25746
25747         DUK_ASSERT_TOP(thr, 3);
25748
25749         /* In some cases it may be that lo > hi, or hi < 0; these
25750          * degenerate cases happen e.g. for empty arrays, and in
25751          * recursion leaves.
25752          */
25753
25754         /* trivial cases */
25755         if (hi - lo < 1) {
25756                 DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately"));
25757                 return;
25758         }
25759         DUK_ASSERT(hi > lo);
25760         DUK_ASSERT(hi - lo + 1 >= 2);
25761
25762         /* randomized pivot selection */
25763         p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE(thr) * (duk_double_t) (hi - lo + 1));
25764         DUK_ASSERT(p >= lo && p <= hi);
25765         DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p));
25766
25767         /* move pivot out of the way */
25768         duk__array_sort_swap(thr, p, lo);
25769         p = lo;
25770         DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(thr, 1)));
25771
25772         l = lo + 1;
25773         r = hi;
25774         for (;;) {
25775                 /* find elements to swap */
25776                 for (;;) {
25777                         DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld",
25778                                              (long) l, (long) r, (long) p));
25779                         if (l >= hi) {
25780                                 break;
25781                         }
25782                         if (duk__array_sort_compare(thr, l, p) >= 0) {  /* !(l < p) */
25783                                 break;
25784                         }
25785                         l++;
25786                 }
25787                 for (;;) {
25788                         DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld",
25789                                              (long) l, (long) r, (long) p));
25790                         if (r <= lo) {
25791                                 break;
25792                         }
25793                         if (duk__array_sort_compare(thr, p, r) >= 0) {  /* !(p < r) */
25794                                 break;
25795                         }
25796                         r--;
25797                 }
25798                 if (l >= r) {
25799                         goto done;
25800                 }
25801                 DUK_ASSERT(l < r);
25802
25803                 DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
25804
25805                 duk__array_sort_swap(thr, l, r);
25806
25807                 DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
25808                 l++;
25809                 r--;
25810         }
25811  done:
25812         /* Note that 'l' and 'r' may cross, i.e. r < l */
25813         DUK_ASSERT(l >= lo && l <= hi);
25814         DUK_ASSERT(r >= lo && r <= hi);
25815
25816         /* XXX: there's no explicit recursion bound here now.  For the average
25817          * qsort recursion depth O(log n) that's not really necessary: e.g. for
25818          * 2**32 recursion depth would be about 32 which is OK.  However, qsort
25819          * worst case recursion depth is O(n) which may be a problem.
25820          */
25821
25822         /* move pivot to its final place */
25823         DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(thr, 1)));
25824         duk__array_sort_swap(thr, lo, r);
25825
25826 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
25827         duk__debuglog_qsort_state(thr, lo, hi, r);
25828 #endif
25829
25830         DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(thr, 1)));
25831         duk__array_qsort(thr, lo, r - 1);
25832         duk__array_qsort(thr, r + 1, hi);
25833 }
25834
25835 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_hthread *thr) {
25836         duk_uint32_t len;
25837
25838         /* XXX: len >= 0x80000000 won't work below because a signed type
25839          * is needed by qsort.
25840          */
25841         len = duk__push_this_obj_len_u32_limited(thr);
25842
25843         /* stack[0] = compareFn
25844          * stack[1] = ToObject(this)
25845          * stack[2] = ToUint32(length)
25846          */
25847
25848         if (len > 0) {
25849                 /* avoid degenerate cases, so that (len - 1) won't underflow */
25850                 duk__array_qsort(thr, (duk_int_t) 0, (duk_int_t) (len - 1));
25851         }
25852
25853         DUK_ASSERT_TOP(thr, 3);
25854         duk_pop_nodecref_unsafe(thr);
25855         return 1;  /* return ToObject(this) */
25856 }
25857
25858 /*
25859  *  splice()
25860  */
25861
25862 /* XXX: this compiles to over 500 bytes now, even without special handling
25863  * for an array part.  Uses signed ints so does not handle full array range correctly.
25864  */
25865
25866 /* XXX: can shift() / unshift() use the same helper?
25867  *   shift() is (close to?) <--> splice(0, 1)
25868  *   unshift is (close to?) <--> splice(0, 0, [items])?
25869  */
25870
25871 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_hthread *thr) {
25872         duk_idx_t nargs;
25873         duk_uint32_t len_u32;
25874         duk_int_t len;
25875         duk_bool_t have_delcount;
25876         duk_int_t item_count;
25877         duk_int_t act_start;
25878         duk_int_t del_count;
25879         duk_int_t i, n;
25880
25881         DUK_UNREF(have_delcount);
25882
25883         nargs = duk_get_top(thr);
25884         if (nargs < 2) {
25885                 duk_set_top(thr, 2);
25886                 nargs = 2;
25887                 have_delcount = 0;
25888         } else {
25889                 have_delcount = 1;
25890         }
25891
25892         /* XXX: len >= 0x80000000 won't work below because we need to be
25893          * able to represent -len.
25894          */
25895         len_u32 = duk__push_this_obj_len_u32_limited(thr);
25896         len = (duk_int_t) len_u32;
25897         DUK_ASSERT(len >= 0);
25898
25899         act_start = duk_to_int_clamped(thr, 0, -len, len);
25900         if (act_start < 0) {
25901                 act_start = len + act_start;
25902         }
25903         DUK_ASSERT(act_start >= 0 && act_start <= len);
25904
25905 #if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
25906         if (have_delcount) {
25907 #endif
25908                 del_count = duk_to_int_clamped(thr, 1, 0, len - act_start);
25909 #if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
25910         } else {
25911                 /* E5.1 standard behavior when deleteCount is not given would be
25912                  * to treat it just like if 'undefined' was given, which coerces
25913                  * ultimately to 0.  Real world behavior is to splice to the end
25914                  * of array, see test-bi-array-proto-splice-no-delcount.js.
25915                  */
25916                 del_count = len - act_start;
25917         }
25918 #endif
25919
25920         DUK_ASSERT(nargs >= 2);
25921         item_count = (duk_int_t) (nargs - 2);
25922
25923         DUK_ASSERT(del_count >= 0 && del_count <= len - act_start);
25924         DUK_ASSERT(del_count + act_start <= len);
25925
25926         /* For now, restrict result array into 32-bit length range. */
25927         if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
25928                 DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
25929                 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
25930         }
25931
25932         duk_push_array(thr);
25933
25934         /* stack[0] = start
25935          * stack[1] = deleteCount
25936          * stack[2...nargs-1] = items
25937          * stack[nargs] = ToObject(this)               -3
25938          * stack[nargs+1] = ToUint32(length)           -2
25939          * stack[nargs+2] = result array               -1
25940          */
25941
25942         DUK_ASSERT_TOP(thr, nargs + 3);
25943
25944         /* Step 9: copy elements-to-be-deleted into the result array */
25945
25946         for (i = 0; i < del_count; i++) {
25947                 if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (act_start + i))) {
25948                         duk_xdef_prop_index_wec(thr, -2, (duk_uarridx_t) i);  /* throw flag irrelevant (false in std alg) */
25949                 } else {
25950                         duk_pop_undefined(thr);
25951                 }
25952         }
25953         duk_push_u32(thr, (duk_uint32_t) del_count);
25954         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
25955
25956         /* Steps 12 and 13: reorganize elements to make room for itemCount elements */
25957
25958         if (item_count < del_count) {
25959                 /*    [ A B C D E F G H ]    rel_index = 2, del_count 3, item count 1
25960                  * -> [ A B F G H ]          (conceptual intermediate step)
25961                  * -> [ A B . F G H ]        (placeholder marked)
25962                  *    [ A B C F G H ]        (actual result at this point, C will be replaced)
25963                  */
25964
25965                 DUK_ASSERT_TOP(thr, nargs + 3);
25966
25967                 n = len - del_count;
25968                 for (i = act_start; i < n; i++) {
25969                         if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
25970                                 duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
25971                         } else {
25972                                 duk_pop_undefined(thr);
25973                                 duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
25974                         }
25975                 }
25976
25977                 DUK_ASSERT_TOP(thr, nargs + 3);
25978
25979                 /* loop iterator init and limit changed from standard algorithm */
25980                 n = len - del_count + item_count;
25981                 for (i = len - 1; i >= n; i--) {
25982                         duk_del_prop_index(thr, -3, (duk_uarridx_t) i);
25983                 }
25984
25985                 DUK_ASSERT_TOP(thr, nargs + 3);
25986         } else if (item_count > del_count) {
25987                 /*    [ A B C D E F G H ]    rel_index = 2, del_count 3, item count 4
25988                  * -> [ A B F G H ]          (conceptual intermediate step)
25989                  * -> [ A B . . . . F G H ]  (placeholder marked)
25990                  *    [ A B C D E F F G H ]  (actual result at this point)
25991                  */
25992
25993                 DUK_ASSERT_TOP(thr, nargs + 3);
25994
25995                 /* loop iterator init and limit changed from standard algorithm */
25996                 for (i = len - del_count - 1; i >= act_start; i--) {
25997                         if (duk_get_prop_index(thr, -3, (duk_uarridx_t) (i + del_count))) {
25998                                 duk_put_prop_index(thr, -4, (duk_uarridx_t) (i + item_count));
25999                         } else {
26000                                 duk_pop_undefined(thr);
26001                                 duk_del_prop_index(thr, -3, (duk_uarridx_t) (i + item_count));
26002                         }
26003                 }
26004
26005                 DUK_ASSERT_TOP(thr, nargs + 3);
26006         } else {
26007                 /*    [ A B C D E F G H ]    rel_index = 2, del_count 3, item count 3
26008                  * -> [ A B F G H ]          (conceptual intermediate step)
26009                  * -> [ A B . . . F G H ]    (placeholder marked)
26010                  *    [ A B C D E F G H ]    (actual result at this point)
26011                  */
26012         }
26013         DUK_ASSERT_TOP(thr, nargs + 3);
26014
26015         /* Step 15: insert itemCount elements into the hole made above */
26016
26017         for (i = 0; i < item_count; i++) {
26018                 duk_dup(thr, i + 2);  /* args start at index 2 */
26019                 duk_put_prop_index(thr, -4, (duk_uarridx_t) (act_start + i));
26020         }
26021
26022         /* Step 16: update length; note that the final length may be above 32 bit range
26023          * (but we checked above that this isn't the case here)
26024          */
26025
26026         duk_push_u32(thr, (duk_uint32_t) (len - del_count + item_count));
26027         duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
26028
26029         /* result array is already at the top of stack */
26030         DUK_ASSERT_TOP(thr, nargs + 3);
26031         return 1;
26032 }
26033
26034 /*
26035  *  reverse()
26036  */
26037
26038 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_hthread *thr) {
26039         duk_uint32_t len;
26040         duk_uint32_t middle;
26041         duk_uint32_t lower, upper;
26042         duk_bool_t have_lower, have_upper;
26043
26044         len = duk__push_this_obj_len_u32(thr);
26045         middle = len / 2;
26046
26047         /* If len <= 1, middle will be 0 and for-loop bails out
26048          * immediately (0 < 0 -> false).
26049          */
26050
26051         for (lower = 0; lower < middle; lower++) {
26052                 DUK_ASSERT(len >= 2);
26053                 DUK_ASSERT_TOP(thr, 2);
26054
26055                 DUK_ASSERT(len >= lower + 1);
26056                 upper = len - lower - 1;
26057
26058                 have_lower = duk_get_prop_index(thr, -2, (duk_uarridx_t) lower);
26059                 have_upper = duk_get_prop_index(thr, -3, (duk_uarridx_t) upper);
26060
26061                 /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
26062
26063                 if (have_upper) {
26064                         duk_put_prop_index(thr, -4, (duk_uarridx_t) lower);
26065                 } else {
26066                         duk_del_prop_index(thr, -4, (duk_uarridx_t) lower);
26067                         duk_pop_undefined(thr);
26068                 }
26069
26070                 if (have_lower) {
26071                         duk_put_prop_index(thr, -3, (duk_uarridx_t) upper);
26072                 } else {
26073                         duk_del_prop_index(thr, -3, (duk_uarridx_t) upper);
26074                         duk_pop_undefined(thr);
26075                 }
26076
26077                 DUK_ASSERT_TOP(thr, 2);
26078         }
26079
26080         DUK_ASSERT_TOP(thr, 2);
26081         duk_pop_unsafe(thr);  /* -> [ ToObject(this) ] */
26082         return 1;
26083 }
26084
26085 /*
26086  *  slice()
26087  */
26088
26089 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_hthread *thr) {
26090         duk_uint32_t len_u32;
26091         duk_int_t len;
26092         duk_int_t start, end;
26093         duk_int_t i;
26094         duk_uarridx_t idx;
26095         duk_uint32_t res_length = 0;
26096
26097         /* XXX: len >= 0x80000000 won't work below because we need to be
26098          * able to represent -len.
26099          */
26100         len_u32 = duk__push_this_obj_len_u32_limited(thr);
26101         len = (duk_int_t) len_u32;
26102         DUK_ASSERT(len >= 0);
26103
26104         duk_push_array(thr);
26105
26106         /* stack[0] = start
26107          * stack[1] = end
26108          * stack[2] = ToObject(this)
26109          * stack[3] = ToUint32(length)
26110          * stack[4] = result array
26111          */
26112
26113         start = duk_to_int_clamped(thr, 0, -len, len);
26114         if (start < 0) {
26115                 start = len + start;
26116         }
26117         /* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
26118          * (the upper limit)?
26119          */
26120         if (duk_is_undefined(thr, 1)) {
26121                 end = len;
26122         } else {
26123                 end = duk_to_int_clamped(thr, 1, -len, len);
26124                 if (end < 0) {
26125                         end = len + end;
26126                 }
26127         }
26128         DUK_ASSERT(start >= 0 && start <= len);
26129         DUK_ASSERT(end >= 0 && end <= len);
26130
26131         idx = 0;
26132         for (i = start; i < end; i++) {
26133                 DUK_ASSERT_TOP(thr, 5);
26134                 if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
26135                         duk_xdef_prop_index_wec(thr, 4, idx);
26136                         res_length = idx + 1;
26137                 } else {
26138                         duk_pop_undefined(thr);
26139                 }
26140                 idx++;
26141                 DUK_ASSERT_TOP(thr, 5);
26142         }
26143
26144         duk_push_u32(thr, res_length);
26145         duk_xdef_prop_stridx_short(thr, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
26146
26147         DUK_ASSERT_TOP(thr, 5);
26148         return 1;
26149 }
26150
26151 /*
26152  *  shift()
26153  */
26154
26155 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_hthread *thr) {
26156         duk_uint32_t len;
26157         duk_uint32_t i;
26158
26159         len = duk__push_this_obj_len_u32(thr);
26160         if (len == 0) {
26161                 duk_push_int(thr, 0);
26162                 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
26163                 return 0;
26164         }
26165
26166         duk_get_prop_index(thr, 0, 0);
26167
26168         /* stack[0] = object (this)
26169          * stack[1] = ToUint32(length)
26170          * stack[2] = elem at index 0 (retval)
26171          */
26172
26173         for (i = 1; i < len; i++) {
26174                 DUK_ASSERT_TOP(thr, 3);
26175                 if (duk_get_prop_index(thr, 0, (duk_uarridx_t) i)) {
26176                         /* fromPresent = true */
26177                         duk_put_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
26178                 } else {
26179                         /* fromPresent = false */
26180                         duk_del_prop_index(thr, 0, (duk_uarridx_t) (i - 1));
26181                         duk_pop_undefined(thr);
26182                 }
26183         }
26184         duk_del_prop_index(thr, 0, (duk_uarridx_t) (len - 1));
26185
26186         duk_push_u32(thr, (duk_uint32_t) (len - 1));
26187         duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
26188
26189         DUK_ASSERT_TOP(thr, 3);
26190         return 1;
26191 }
26192
26193 /*
26194  *  unshift()
26195  */
26196
26197 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_hthread *thr) {
26198         duk_idx_t nargs;
26199         duk_uint32_t len;
26200         duk_uint32_t i;
26201
26202         nargs = duk_get_top(thr);
26203         len = duk__push_this_obj_len_u32(thr);
26204
26205         /* stack[0...nargs-1] = unshift args (vararg)
26206          * stack[nargs] = ToObject(this)
26207          * stack[nargs+1] = ToUint32(length)
26208          */
26209
26210         DUK_ASSERT_TOP(thr, nargs + 2);
26211
26212         /* Note: unshift() may operate on indices above unsigned 32-bit range
26213          * and the final length may be >= 2**32.  However, we restrict the
26214          * final result to 32-bit range for practicality.
26215          */
26216
26217         if (len + (duk_uint32_t) nargs < len) {
26218                 DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
26219                 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
26220         }
26221
26222         i = len;
26223         while (i > 0) {
26224                 DUK_ASSERT_TOP(thr, nargs + 2);
26225                 i--;
26226                 /* k+argCount-1; note that may be above 32-bit range */
26227
26228                 if (duk_get_prop_index(thr, -2, (duk_uarridx_t) i)) {
26229                         /* fromPresent = true */
26230                         /* [ ... ToObject(this) ToUint32(length) val ] */
26231                         duk_put_prop_index(thr, -3, (duk_uarridx_t) (i + (duk_uint32_t) nargs));  /* -> [ ... ToObject(this) ToUint32(length) ] */
26232                 } else {
26233                         /* fromPresent = false */
26234                         /* [ ... ToObject(this) ToUint32(length) val ] */
26235                         duk_pop_undefined(thr);
26236                         duk_del_prop_index(thr, -2, (duk_uarridx_t) (i + (duk_uint32_t) nargs));  /* -> [ ... ToObject(this) ToUint32(length) ] */
26237                 }
26238                 DUK_ASSERT_TOP(thr, nargs + 2);
26239         }
26240
26241         for (i = 0; i < (duk_uint32_t) nargs; i++) {
26242                 DUK_ASSERT_TOP(thr, nargs + 2);
26243                 duk_dup(thr, (duk_idx_t) i);  /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
26244                 duk_put_prop_index(thr, -3, (duk_uarridx_t) i);
26245                 DUK_ASSERT_TOP(thr, nargs + 2);
26246         }
26247
26248         DUK_ASSERT_TOP(thr, nargs + 2);
26249         duk_push_u32(thr, len + (duk_uint32_t) nargs);
26250         duk_dup_top(thr);  /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
26251         duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_LENGTH);
26252         return 1;
26253 }
26254
26255 /*
26256  *  indexOf(), lastIndexOf()
26257  */
26258
26259 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_hthread *thr) {
26260         duk_idx_t nargs;
26261         duk_int_t i, len;
26262         duk_int_t from_idx;
26263         duk_small_int_t idx_step = duk_get_current_magic(thr);  /* idx_step is +1 for indexOf, -1 for lastIndexOf */
26264
26265         /* lastIndexOf() needs to be a vararg function because we must distinguish
26266          * between an undefined fromIndex and a "not given" fromIndex; indexOf() is
26267          * made vararg for symmetry although it doesn't strictly need to be.
26268          */
26269
26270         nargs = duk_get_top(thr);
26271         duk_set_top(thr, 2);
26272
26273         /* XXX: must be able to represent -len */
26274         len = (duk_int_t) duk__push_this_obj_len_u32_limited(thr);
26275         if (len == 0) {
26276                 goto not_found;
26277         }
26278
26279         /* Index clamping is a bit tricky, we must ensure that we'll only iterate
26280          * through elements that exist and that the specific requirements from E5.1
26281          * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially:
26282          *
26283          *   - indexOf: clamp to [-len,len], negative handling -> [0,len],
26284          *     if clamped result is len, for-loop bails out immediately
26285          *
26286          *   - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1],
26287          *     if clamped result is -1, for-loop bails out immediately
26288          *
26289          * If fromIndex is not given, ToInteger(undefined) = 0, which is correct
26290          * for indexOf() but incorrect for lastIndexOf().  Hence special handling,
26291          * and why lastIndexOf() needs to be a vararg function.
26292          */
26293
26294         if (nargs >= 2) {
26295                 /* indexOf: clamp fromIndex to [-len, len]
26296                  * (if fromIndex == len, for-loop terminates directly)
26297                  *
26298                  * lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
26299                  * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
26300                  */
26301                 from_idx = duk_to_int_clamped(thr,
26302                                               1,
26303                                               (idx_step > 0 ? -len : -len - 1),
26304                                               (idx_step > 0 ? len : len - 1));
26305                 if (from_idx < 0) {
26306                         /* for lastIndexOf, result may be -1 (mark immediate termination) */
26307                         from_idx = len + from_idx;
26308                 }
26309         } else {
26310                 /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
26311                  * handle both indexOf and lastIndexOf specially here.
26312                  */
26313                 if (idx_step > 0) {
26314                         from_idx = 0;
26315                 } else {
26316                         from_idx = len - 1;
26317                 }
26318         }
26319
26320         /* stack[0] = searchElement
26321          * stack[1] = fromIndex
26322          * stack[2] = object
26323          * stack[3] = length (not needed, but not popped above)
26324          */
26325
26326         for (i = from_idx; i >= 0 && i < len; i += idx_step) {
26327                 DUK_ASSERT_TOP(thr, 4);
26328
26329                 if (duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
26330                         DUK_ASSERT_TOP(thr, 5);
26331                         if (duk_strict_equals(thr, 0, 4)) {
26332                                 duk_push_int(thr, i);
26333                                 return 1;
26334                         }
26335                 }
26336
26337                 duk_pop_unsafe(thr);
26338         }
26339
26340  not_found:
26341         duk_push_int(thr, -1);
26342         return 1;
26343 }
26344
26345 /*
26346  *  every(), some(), forEach(), map(), filter()
26347  */
26348
26349 #define DUK__ITER_EVERY    0
26350 #define DUK__ITER_SOME     1
26351 #define DUK__ITER_FOREACH  2
26352 #define DUK__ITER_MAP      3
26353 #define DUK__ITER_FILTER   4
26354
26355 /* XXX: This helper is a bit awkward because the handling for the different iteration
26356  * callers is quite different.  This now compiles to a bit less than 500 bytes, so with
26357  * 5 callers the net result is about 100 bytes / caller.
26358  */
26359
26360 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_hthread *thr) {
26361         duk_uint32_t len;
26362         duk_uint32_t i;
26363         duk_uarridx_t k;
26364         duk_bool_t bval;
26365         duk_small_int_t iter_type = duk_get_current_magic(thr);
26366         duk_uint32_t res_length = 0;
26367
26368         /* each call this helper serves has nargs==2 */
26369         DUK_ASSERT_TOP(thr, 2);
26370
26371         len = duk__push_this_obj_len_u32(thr);
26372         duk_require_callable(thr, 0);
26373         /* if thisArg not supplied, behave as if undefined was supplied */
26374
26375         if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
26376                 duk_push_array(thr);
26377         } else {
26378                 duk_push_undefined(thr);
26379         }
26380
26381         /* stack[0] = callback
26382          * stack[1] = thisArg
26383          * stack[2] = object
26384          * stack[3] = ToUint32(length)  (unused, but avoid unnecessary pop)
26385          * stack[4] = result array (or undefined)
26386          */
26387
26388         k = 0;  /* result index for filter() */
26389         for (i = 0; i < len; i++) {
26390                 DUK_ASSERT_TOP(thr, 5);
26391
26392                 if (!duk_get_prop_index(thr, 2, (duk_uarridx_t) i)) {
26393                         /* For 'map' trailing missing elements don't invoke the
26394                          * callback but count towards the result length.
26395                          */
26396                         if (iter_type == DUK__ITER_MAP) {
26397                                 res_length = i + 1;
26398                         }
26399                         duk_pop_undefined(thr);
26400                         continue;
26401                 }
26402
26403                 /* The original value needs to be preserved for filter(), hence
26404                  * this funny order.  We can't re-get the value because of side
26405                  * effects.
26406                  */
26407
26408                 duk_dup_0(thr);
26409                 duk_dup_1(thr);
26410                 duk_dup_m3(thr);
26411                 duk_push_u32(thr, i);
26412                 duk_dup_2(thr);  /* [ ... val callback thisArg val i obj ] */
26413                 duk_call_method(thr, 3); /* -> [ ... val retval ] */
26414
26415                 switch (iter_type) {
26416                 case DUK__ITER_EVERY:
26417                         bval = duk_to_boolean(thr, -1);
26418                         if (!bval) {
26419                                 /* stack top contains 'false' */
26420                                 return 1;
26421                         }
26422                         break;
26423                 case DUK__ITER_SOME:
26424                         bval = duk_to_boolean(thr, -1);
26425                         if (bval) {
26426                                 /* stack top contains 'true' */
26427                                 return 1;
26428                         }
26429                         break;
26430                 case DUK__ITER_FOREACH:
26431                         /* nop */
26432                         break;
26433                 case DUK__ITER_MAP:
26434                         duk_dup_top(thr);
26435                         duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) i);  /* retval to result[i] */
26436                         res_length = i + 1;
26437                         break;
26438                 case DUK__ITER_FILTER:
26439                         bval = duk_to_boolean(thr, -1);
26440                         if (bval) {
26441                                 duk_dup_m2(thr);  /* orig value */
26442                                 duk_xdef_prop_index_wec(thr, 4, (duk_uarridx_t) k);
26443                                 k++;
26444                                 res_length = k;
26445                         }
26446                         break;
26447                 default:
26448                         DUK_UNREACHABLE();
26449                         break;
26450                 }
26451                 duk_pop_2_unsafe(thr);
26452
26453                 DUK_ASSERT_TOP(thr, 5);
26454         }
26455
26456         switch (iter_type) {
26457         case DUK__ITER_EVERY:
26458                 duk_push_true(thr);
26459                 break;
26460         case DUK__ITER_SOME:
26461                 duk_push_false(thr);
26462                 break;
26463         case DUK__ITER_FOREACH:
26464                 duk_push_undefined(thr);
26465                 break;
26466         case DUK__ITER_MAP:
26467         case DUK__ITER_FILTER:
26468                 DUK_ASSERT_TOP(thr, 5);
26469                 DUK_ASSERT(duk_is_array(thr, -1));  /* topmost element is the result array already */
26470                 duk_push_u32(thr, res_length);
26471                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
26472                 break;
26473         default:
26474                 DUK_UNREACHABLE();
26475                 break;
26476         }
26477
26478         return 1;
26479 }
26480
26481 /*
26482  *  reduce(), reduceRight()
26483  */
26484
26485 DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_hthread *thr) {
26486         duk_idx_t nargs;
26487         duk_bool_t have_acc;
26488         duk_uint32_t i, len;
26489         duk_small_int_t idx_step = duk_get_current_magic(thr);  /* idx_step is +1 for reduce, -1 for reduceRight */
26490
26491         /* We're a varargs function because we need to detect whether
26492          * initialValue was given or not.
26493          */
26494         nargs = duk_get_top(thr);
26495         DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
26496
26497         duk_set_top(thr, 2);
26498         len = duk__push_this_obj_len_u32(thr);
26499         duk_require_callable(thr, 0);
26500
26501         /* stack[0] = callback fn
26502          * stack[1] = initialValue
26503          * stack[2] = object (coerced this)
26504          * stack[3] = length (not needed, but not popped above)
26505          * stack[4] = accumulator
26506          */
26507
26508         have_acc = 0;
26509         if (nargs >= 2) {
26510                 duk_dup_1(thr);
26511                 have_acc = 1;
26512         }
26513         DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
26514                              (long) have_acc, (duk_tval *) duk_get_tval(thr, 3)));
26515
26516         /* For len == 0, i is initialized to len - 1 which underflows.
26517          * The condition (i < len) will then exit the for-loop on the
26518          * first round which is correct.  Similarly, loop termination
26519          * happens by i underflowing.
26520          */
26521
26522         for (i = (idx_step >= 0 ? 0 : len - 1);
26523              i < len;  /* i >= 0 would always be true */
26524              i += (duk_uint32_t) idx_step) {
26525                 DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
26526                                      (long) i, (long) len, (long) have_acc,
26527                                      (long) duk_get_top(thr),
26528                                      (duk_tval *) duk_get_tval(thr, 4)));
26529
26530                 DUK_ASSERT((have_acc && duk_get_top(thr) == 5) ||
26531                            (!have_acc && duk_get_top(thr) == 4));
26532
26533                 if (!duk_has_prop_index(thr, 2, (duk_uarridx_t) i)) {
26534                         continue;
26535                 }
26536
26537                 if (!have_acc) {
26538                         DUK_ASSERT_TOP(thr, 4);
26539                         duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
26540                         have_acc = 1;
26541                         DUK_ASSERT_TOP(thr, 5);
26542                 } else {
26543                         DUK_ASSERT_TOP(thr, 5);
26544                         duk_dup_0(thr);
26545                         duk_dup(thr, 4);
26546                         duk_get_prop_index(thr, 2, (duk_uarridx_t) i);
26547                         duk_push_u32(thr, i);
26548                         duk_dup_2(thr);
26549                         DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
26550                                              (duk_tval *) duk_get_tval(thr, -5), (duk_tval *) duk_get_tval(thr, -4),
26551                                              (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
26552                                              (duk_tval *) duk_get_tval(thr, -1)));
26553                         duk_call(thr, 4);
26554                         DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
26555                         duk_replace(thr, 4);
26556                         DUK_ASSERT_TOP(thr, 5);
26557                 }
26558         }
26559
26560         if (!have_acc) {
26561                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
26562         }
26563
26564         DUK_ASSERT_TOP(thr, 5);
26565         return 1;
26566 }
26567
26568 #endif  /* DUK_USE_ARRAY_BUILTIN */
26569
26570 /* automatic undefs */
26571 #undef DUK__ARRAY_MID_JOIN_LIMIT
26572 #undef DUK__ITER_EVERY
26573 #undef DUK__ITER_FILTER
26574 #undef DUK__ITER_FOREACH
26575 #undef DUK__ITER_MAP
26576 #undef DUK__ITER_SOME
26577 #line 1 "duk_bi_boolean.c"
26578 /*
26579  *  Boolean built-ins
26580  */
26581
26582 /* #include duk_internal.h -> already included */
26583
26584 #if defined(DUK_USE_BOOLEAN_BUILTIN)
26585
26586 /* Shared helper to provide toString() and valueOf().  Checks 'this', gets
26587  * the primitive value to stack top, and optionally coerces with ToString().
26588  */
26589 DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_hthread *thr) {
26590         duk_tval *tv;
26591         duk_hobject *h;
26592         duk_small_int_t coerce_tostring = duk_get_current_magic(thr);
26593
26594         /* XXX: there is room to use a shared helper here, many built-ins
26595          * check the 'this' type, and if it's an object, check its class,
26596          * then get its internal value, etc.
26597          */
26598
26599         duk_push_this(thr);
26600         tv = duk_get_tval(thr, -1);
26601         DUK_ASSERT(tv != NULL);
26602
26603         if (DUK_TVAL_IS_BOOLEAN(tv)) {
26604                 goto type_ok;
26605         } else if (DUK_TVAL_IS_OBJECT(tv)) {
26606                 h = DUK_TVAL_GET_OBJECT(tv);
26607                 DUK_ASSERT(h != NULL);
26608
26609                 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
26610                         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
26611                         DUK_ASSERT(duk_is_boolean(thr, -1));
26612                         goto type_ok;
26613                 }
26614         }
26615
26616         DUK_DCERROR_TYPE_INVALID_ARGS(thr);
26617         /* never here */
26618
26619  type_ok:
26620         if (coerce_tostring) {
26621                 duk_to_string(thr, -1);
26622         }
26623         return 1;
26624 }
26625
26626 DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_hthread *thr) {
26627         duk_hobject *h_this;
26628
26629         duk_to_boolean(thr, 0);
26630
26631         if (duk_is_constructor_call(thr)) {
26632                 /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
26633                 duk_push_this(thr);
26634                 h_this = duk_known_hobject(thr, -1);
26635                 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
26636
26637                 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
26638
26639                 duk_dup_0(thr);  /* -> [ val obj val ] */
26640                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);  /* XXX: proper flags? */
26641         }  /* unbalanced stack */
26642
26643         return 1;
26644 }
26645
26646 #endif  /* DUK_USE_BOOLEAN_BUILTIN */
26647 #line 1 "duk_bi_buffer.c"
26648 /*
26649  *  ES2015 TypedArray and Node.js Buffer built-ins
26650  */
26651
26652 /* #include duk_internal.h -> already included */
26653
26654 /*
26655  *  Helpers for buffer handling, enabled with DUK_USE_BUFFEROBJECT_SUPPORT.
26656  */
26657
26658 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
26659 /* Map class number (minus DUK_HOBJECT_CLASS_BUFOBJ_MIN) to a bidx for the
26660  * default internal prototype.
26661  */
26662 static const duk_uint8_t duk__buffer_proto_from_classnum[] = {
26663         DUK_BIDX_ARRAYBUFFER_PROTOTYPE,
26664         DUK_BIDX_DATAVIEW_PROTOTYPE,
26665         DUK_BIDX_INT8ARRAY_PROTOTYPE,
26666         DUK_BIDX_UINT8ARRAY_PROTOTYPE,
26667         DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
26668         DUK_BIDX_INT16ARRAY_PROTOTYPE,
26669         DUK_BIDX_UINT16ARRAY_PROTOTYPE,
26670         DUK_BIDX_INT32ARRAY_PROTOTYPE,
26671         DUK_BIDX_UINT32ARRAY_PROTOTYPE,
26672         DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
26673         DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
26674 };
26675
26676 /* Map DUK_HBUFOBJ_ELEM_xxx to duk_hobject class number.
26677  * Sync with duk_hbufobj.h and duk_hobject.h.
26678  */
26679 static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
26680         DUK_HOBJECT_CLASS_UINT8ARRAY,
26681         DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY,
26682         DUK_HOBJECT_CLASS_INT8ARRAY,
26683         DUK_HOBJECT_CLASS_UINT16ARRAY,
26684         DUK_HOBJECT_CLASS_INT16ARRAY,
26685         DUK_HOBJECT_CLASS_UINT32ARRAY,
26686         DUK_HOBJECT_CLASS_INT32ARRAY,
26687         DUK_HOBJECT_CLASS_FLOAT32ARRAY,
26688         DUK_HOBJECT_CLASS_FLOAT64ARRAY
26689 };
26690
26691 /* Map DUK_HBUFOBJ_ELEM_xxx to prototype object built-in index.
26692  * Sync with duk_hbufobj.h.
26693  */
26694 static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
26695         DUK_BIDX_UINT8ARRAY_PROTOTYPE,
26696         DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
26697         DUK_BIDX_INT8ARRAY_PROTOTYPE,
26698         DUK_BIDX_UINT16ARRAY_PROTOTYPE,
26699         DUK_BIDX_INT16ARRAY_PROTOTYPE,
26700         DUK_BIDX_UINT32ARRAY_PROTOTYPE,
26701         DUK_BIDX_INT32ARRAY_PROTOTYPE,
26702         DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
26703         DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
26704 };
26705
26706 /* Map DUK__FLD_xxx to byte size. */
26707 static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
26708         1,  /* DUK__FLD_8BIT */
26709         2,  /* DUK__FLD_16BIT */
26710         4,  /* DUK__FLD_32BIT */
26711         4,  /* DUK__FLD_FLOAT */
26712         8,  /* DUK__FLD_DOUBLE */
26713         0   /* DUK__FLD_VARINT; not relevant here */
26714 };
26715
26716 /* Bitfield for each DUK_HBUFOBJ_ELEM_xxx indicating which element types
26717  * are compatible with a blind byte copy for the TypedArray set() method (also
26718  * used for TypedArray constructor).  Array index is target buffer elem type,
26719  * bitfield indicates compatible source types.  The types must have same byte
26720  * size and they must be coercion compatible.
26721  */
26722 #if !defined(DUK_USE_PREFER_SIZE)
26723 static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
26724         /* xxx -> DUK_HBUFOBJ_ELEM_UINT8 */
26725         (1U << DUK_HBUFOBJ_ELEM_UINT8) |
26726                 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
26727                 (1U << DUK_HBUFOBJ_ELEM_INT8),
26728
26729         /* xxx -> DUK_HBUFOBJ_ELEM_UINT8CLAMPED
26730          * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00.
26731          */
26732         (1U << DUK_HBUFOBJ_ELEM_UINT8) |
26733                 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED),
26734
26735         /* xxx -> DUK_HBUFOBJ_ELEM_INT8 */
26736         (1U << DUK_HBUFOBJ_ELEM_UINT8) |
26737                 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
26738                 (1U << DUK_HBUFOBJ_ELEM_INT8),
26739
26740         /* xxx -> DUK_HBUFOBJ_ELEM_UINT16 */
26741         (1U << DUK_HBUFOBJ_ELEM_UINT16) |
26742                 (1U << DUK_HBUFOBJ_ELEM_INT16),
26743
26744         /* xxx -> DUK_HBUFOBJ_ELEM_INT16 */
26745         (1U << DUK_HBUFOBJ_ELEM_UINT16) |
26746                 (1U << DUK_HBUFOBJ_ELEM_INT16),
26747
26748         /* xxx -> DUK_HBUFOBJ_ELEM_UINT32 */
26749         (1U << DUK_HBUFOBJ_ELEM_UINT32) |
26750                 (1U << DUK_HBUFOBJ_ELEM_INT32),
26751
26752         /* xxx -> DUK_HBUFOBJ_ELEM_INT32 */
26753         (1U << DUK_HBUFOBJ_ELEM_UINT32) |
26754                 (1U << DUK_HBUFOBJ_ELEM_INT32),
26755
26756         /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT32 */
26757         (1U << DUK_HBUFOBJ_ELEM_FLOAT32),
26758
26759         /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT64 */
26760         (1U << DUK_HBUFOBJ_ELEM_FLOAT64)
26761 };
26762 #endif  /* !DUK_USE_PREFER_SIZE */
26763
26764 DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_hthread *thr) {
26765         duk_tval *tv_dst;
26766         duk_hbufobj *res;
26767
26768         duk_push_this(thr);
26769         DUK_ASSERT(duk_is_buffer(thr, -1));
26770         res = (duk_hbufobj *) duk_to_hobject(thr, -1);
26771         DUK_ASSERT_HBUFOBJ_VALID(res);
26772         DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(thr, -1)));
26773
26774         tv_dst = duk_get_borrowed_this_tval(thr);
26775         DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res);
26776         duk_pop(thr);
26777
26778         return res;
26779 }
26780
26781 #define DUK__BUFOBJ_FLAG_THROW    (1 << 0)
26782 #define DUK__BUFOBJ_FLAG_PROMOTE  (1 << 1)
26783
26784 /* Shared helper.  When DUK__BUFOBJ_FLAG_PROMOTE is given, the return value is
26785  * always a duk_hbufobj *.  Without the flag the return value can also be a
26786  * plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER().
26787  */
26788 DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_hthread *thr, duk_small_uint_t flags) {
26789         duk_tval *tv;
26790         duk_hbufobj *h_this;
26791
26792         DUK_ASSERT(thr != NULL);
26793
26794         tv = duk_get_borrowed_this_tval(thr);
26795         DUK_ASSERT(tv != NULL);
26796
26797         if (DUK_TVAL_IS_OBJECT(tv)) {
26798                 h_this = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
26799                 DUK_ASSERT(h_this != NULL);
26800                 if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_this)) {
26801                         DUK_ASSERT_HBUFOBJ_VALID(h_this);
26802                         return (duk_heaphdr *) h_this;
26803                 }
26804         } else if (DUK_TVAL_IS_BUFFER(tv)) {
26805                 if (flags & DUK__BUFOBJ_FLAG_PROMOTE) {
26806                         /* Promote a plain buffer to a Uint8Array.  This is very
26807                          * inefficient but allows plain buffer to be used wherever an
26808                          * Uint8Array is used with very small cost; hot path functions
26809                          * like index read/write calls should provide direct buffer
26810                          * support to avoid promotion.
26811                          */
26812                         /* XXX: make this conditional to a flag if call sites need it? */
26813                         h_this = duk__hbufobj_promote_this(thr);
26814                         DUK_ASSERT(h_this != NULL);
26815                         DUK_ASSERT_HBUFOBJ_VALID(h_this);
26816                         return (duk_heaphdr *) h_this;
26817                 } else {
26818                         /* XXX: ugly, share return pointer for duk_hbuffer. */
26819                         return (duk_heaphdr *) DUK_TVAL_GET_BUFFER(tv);
26820                 }
26821         }
26822
26823         if (flags & DUK__BUFOBJ_FLAG_THROW) {
26824                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
26825                 DUK_WO_NORETURN(return NULL;);
26826         }
26827         return NULL;
26828 }
26829
26830 /* Check that 'this' is a duk_hbufobj and return a pointer to it. */
26831 DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_hthread *thr) {
26832         return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_PROMOTE);
26833 }
26834
26835 /* Check that 'this' is a duk_hbufobj and return a pointer to it
26836  * (NULL if not).
26837  */
26838 DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_hthread *thr) {
26839         return (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE);
26840 }
26841
26842 /* Check that value is a duk_hbufobj and return a pointer to it. */
26843 DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_hthread *thr, duk_idx_t idx) {
26844         duk_tval *tv;
26845         duk_hbufobj *h_obj;
26846
26847         /* Don't accept relative indices now. */
26848         DUK_ASSERT(idx >= 0);
26849
26850         tv = duk_require_tval(thr, idx);
26851         DUK_ASSERT(tv != NULL);
26852         if (DUK_TVAL_IS_OBJECT(tv)) {
26853                 h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
26854                 DUK_ASSERT(h_obj != NULL);
26855                 if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_obj)) {
26856                         DUK_ASSERT_HBUFOBJ_VALID(h_obj);
26857                         return h_obj;
26858                 }
26859         } else if (DUK_TVAL_IS_BUFFER(tv)) {
26860                 h_obj = (duk_hbufobj *) duk_to_hobject(thr, idx);
26861                 DUK_ASSERT(h_obj != NULL);
26862                 DUK_ASSERT_HBUFOBJ_VALID(h_obj);
26863                 return h_obj;
26864         }
26865
26866         DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
26867         DUK_WO_NORETURN(return NULL;);
26868 }
26869
26870 DUK_LOCAL void duk__set_bufobj_buffer(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) {
26871         DUK_ASSERT(thr != NULL);
26872         DUK_ASSERT(h_bufobj != NULL);
26873         DUK_ASSERT(h_bufobj->buf == NULL);  /* no need to decref */
26874         DUK_ASSERT(h_val != NULL);
26875         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
26876         DUK_UNREF(thr);
26877
26878         h_bufobj->buf = h_val;
26879         DUK_HBUFFER_INCREF(thr, h_val);
26880         h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
26881         DUK_ASSERT(h_bufobj->shift == 0);
26882         DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
26883         DUK_ASSERT(h_bufobj->is_typedarray == 0);
26884
26885         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
26886 }
26887
26888 /* Shared offset/length coercion helper. */
26889 DUK_LOCAL void duk__resolve_offset_opt_length(duk_hthread *thr,
26890                                               duk_hbufobj *h_bufarg,
26891                                               duk_idx_t idx_offset,
26892                                               duk_idx_t idx_length,
26893                                               duk_uint_t *out_offset,
26894                                               duk_uint_t *out_length,
26895                                               duk_bool_t throw_flag) {
26896         duk_int_t offset_signed;
26897         duk_int_t length_signed;
26898         duk_uint_t offset;
26899         duk_uint_t length;
26900
26901         offset_signed = duk_to_int(thr, idx_offset);
26902         if (offset_signed < 0) {
26903                 goto fail_range;
26904         }
26905         offset = (duk_uint_t) offset_signed;
26906         if (offset > h_bufarg->length) {
26907                 goto fail_range;
26908         }
26909         DUK_ASSERT_DISABLE(offset >= 0);  /* unsigned */
26910         DUK_ASSERT(offset <= h_bufarg->length);
26911
26912         if (duk_is_undefined(thr, idx_length)) {
26913                 DUK_ASSERT(h_bufarg->length >= offset);
26914                 length = h_bufarg->length - offset;  /* >= 0 */
26915         } else {
26916                 length_signed = duk_to_int(thr, idx_length);
26917                 if (length_signed < 0) {
26918                         goto fail_range;
26919                 }
26920                 length = (duk_uint_t) length_signed;
26921                 DUK_ASSERT(h_bufarg->length >= offset);
26922                 if (length > h_bufarg->length - offset) {
26923                         /* Unlike for negative arguments, some call sites
26924                          * want length to be clamped if it's positive.
26925                          */
26926                         if (throw_flag) {
26927                                 goto fail_range;
26928                         } else {
26929                                 length = h_bufarg->length - offset;
26930                         }
26931                 }
26932         }
26933         DUK_ASSERT_DISABLE(length >= 0);  /* unsigned */
26934         DUK_ASSERT(offset + length <= h_bufarg->length);
26935
26936         *out_offset = offset;
26937         *out_length = length;
26938         return;
26939
26940  fail_range:
26941         DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
26942         DUK_WO_NORETURN(return;);
26943 }
26944
26945 /* Shared lenient buffer length clamping helper.  No negative indices, no
26946  * element/byte shifting.
26947  */
26948 DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_hthread *thr,
26949                                                     duk_int_t buffer_length,
26950                                                     duk_idx_t idx_start,
26951                                                     duk_idx_t idx_end,
26952                                                     duk_int_t *out_start_offset,
26953                                                     duk_int_t *out_end_offset) {
26954         duk_int_t start_offset;
26955         duk_int_t end_offset;
26956
26957         DUK_ASSERT(out_start_offset != NULL);
26958         DUK_ASSERT(out_end_offset != NULL);
26959
26960         /* undefined coerces to zero which is correct */
26961         start_offset = duk_to_int_clamped(thr, idx_start, 0, buffer_length);
26962         if (duk_is_undefined(thr, idx_end)) {
26963                 end_offset = buffer_length;
26964         } else {
26965                 end_offset = duk_to_int_clamped(thr, idx_end, start_offset, buffer_length);
26966         }
26967
26968         DUK_ASSERT(start_offset >= 0);
26969         DUK_ASSERT(start_offset <= buffer_length);
26970         DUK_ASSERT(end_offset >= 0);
26971         DUK_ASSERT(end_offset <= buffer_length);
26972         DUK_ASSERT(start_offset <= end_offset);
26973
26974         *out_start_offset = start_offset;
26975         *out_end_offset = end_offset;
26976 }
26977
26978 /* Shared lenient buffer length clamping helper.  Indices are treated as
26979  * element indices (though output values are byte offsets) which only
26980  * really matters for TypedArray views as other buffer object have a zero
26981  * shift.  Negative indices are counted from end of input slice; crossed
26982  * indices are clamped to zero length; and final indices are clamped
26983  * against input slice.  Used for e.g. ArrayBuffer slice().
26984  */
26985 DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_hthread *thr,
26986                                                   duk_int_t buffer_length,
26987                                                   duk_uint8_t buffer_shift,
26988                                                   duk_idx_t idx_start,
26989                                                   duk_idx_t idx_end,
26990                                                   duk_int_t *out_start_offset,
26991                                                   duk_int_t *out_end_offset) {
26992         duk_int_t start_offset;
26993         duk_int_t end_offset;
26994
26995         DUK_ASSERT(out_start_offset != NULL);
26996         DUK_ASSERT(out_end_offset != NULL);
26997
26998         buffer_length >>= buffer_shift;  /* as (full) elements */
26999
27000         /* Resolve start/end offset as element indices first; arguments
27001          * at idx_start/idx_end are element offsets.  Working with element
27002          * indices first also avoids potential for wrapping.
27003          */
27004
27005         start_offset = duk_to_int(thr, idx_start);
27006         if (start_offset < 0) {
27007                 start_offset = buffer_length + start_offset;
27008         }
27009         if (duk_is_undefined(thr, idx_end)) {
27010                 end_offset = buffer_length;
27011         } else {
27012                 end_offset = duk_to_int(thr, idx_end);
27013                 if (end_offset < 0) {
27014                         end_offset = buffer_length + end_offset;
27015                 }
27016         }
27017         /* Note: start_offset/end_offset can still be < 0 here. */
27018
27019         if (start_offset < 0) {
27020                 start_offset = 0;
27021         } else if (start_offset > buffer_length) {
27022                 start_offset = buffer_length;
27023         }
27024         if (end_offset < start_offset) {
27025                 end_offset = start_offset;
27026         } else if (end_offset > buffer_length) {
27027                 end_offset = buffer_length;
27028         }
27029         DUK_ASSERT(start_offset >= 0);
27030         DUK_ASSERT(start_offset <= buffer_length);
27031         DUK_ASSERT(end_offset >= 0);
27032         DUK_ASSERT(end_offset <= buffer_length);
27033         DUK_ASSERT(start_offset <= end_offset);
27034
27035         /* Convert indices to byte offsets. */
27036         start_offset <<= buffer_shift;
27037         end_offset <<= buffer_shift;
27038
27039         *out_start_offset = start_offset;
27040         *out_end_offset = end_offset;
27041 }
27042
27043 DUK_INTERNAL void duk_hbufobj_promote_plain(duk_hthread *thr, duk_idx_t idx) {
27044         if (duk_is_buffer(thr, idx)) {
27045                 duk_to_object(thr, idx);
27046         }
27047 }
27048
27049 DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) {
27050         /* Push Uint8Array which will share the same underlying buffer as
27051          * the plain buffer argument.  Also create an ArrayBuffer with the
27052          * same backing for the result .buffer property.
27053          */
27054
27055         duk_push_hbuffer(thr, h_buf);
27056         duk_push_buffer_object(thr, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY);
27057         duk_remove_m2(thr);
27058
27059 #if 0
27060         /* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */
27061         h_bufobj = duk_push_bufobj_raw(thr,
27062                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
27063                                        DUK_HOBJECT_FLAG_BUFOBJ |
27064                                        DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
27065                                        DUK_BIDX_UINT8ARRAY_PROTOTYPE);
27066         DUK_ASSERT(h_bufobj != NULL);
27067         duk__set_bufobj_buffer(thr, h_bufobj, h_buf);
27068         h_bufobj->is_typedarray = 1;
27069         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
27070
27071         h_arrbuf = duk_push_bufobj_raw(thr,
27072                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
27073                                        DUK_HOBJECT_FLAG_BUFOBJ |
27074                                        DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
27075                                        DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
27076         DUK_ASSERT(h_arrbuf != NULL);
27077         duk__set_bufobj_buffer(thr, h_arrbuf, h_buf);
27078         DUK_ASSERT(h_arrbuf->is_typedarray == 0);
27079         DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf);
27080
27081         DUK_ASSERT(h_bufobj->buf_prop == NULL);
27082         h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
27083         DUK_ASSERT(h_arrbuf != NULL);
27084         DUK_HBUFOBJ_INCREF(thr, h_arrbuf);
27085         duk_pop(thr);
27086 #endif
27087 }
27088
27089 /* Indexed read helper for buffer objects, also called from outside this file. */
27090 DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
27091         duk_double_union du;
27092
27093         DUK_ASSERT(elem_size > 0);
27094         duk_memcpy((void *) du.uc, (const void *) p, (size_t) elem_size);
27095
27096         switch (h_bufobj->elem_type) {
27097         case DUK_HBUFOBJ_ELEM_UINT8:
27098         case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
27099                 duk_push_uint(thr, (duk_uint_t) du.uc[0]);
27100                 break;
27101         case DUK_HBUFOBJ_ELEM_INT8:
27102                 duk_push_int(thr, (duk_int_t) (duk_int8_t) du.uc[0]);
27103                 break;
27104         case DUK_HBUFOBJ_ELEM_UINT16:
27105                 duk_push_uint(thr, (duk_uint_t) du.us[0]);
27106                 break;
27107         case DUK_HBUFOBJ_ELEM_INT16:
27108                 duk_push_int(thr, (duk_int_t) (duk_int16_t) du.us[0]);
27109                 break;
27110         case DUK_HBUFOBJ_ELEM_UINT32:
27111                 duk_push_uint(thr, (duk_uint_t) du.ui[0]);
27112                 break;
27113         case DUK_HBUFOBJ_ELEM_INT32:
27114                 duk_push_int(thr, (duk_int_t) (duk_int32_t) du.ui[0]);
27115                 break;
27116         case DUK_HBUFOBJ_ELEM_FLOAT32:
27117                 duk_push_number(thr, (duk_double_t) du.f[0]);
27118                 break;
27119         case DUK_HBUFOBJ_ELEM_FLOAT64:
27120                 duk_push_number(thr, (duk_double_t) du.d);
27121                 break;
27122         default:
27123                 DUK_UNREACHABLE();
27124         }
27125 }
27126
27127 /* Indexed write helper for buffer objects, also called from outside this file. */
27128 DUK_INTERNAL void duk_hbufobj_validated_write(duk_hthread *thr, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
27129         duk_double_union du;
27130
27131         /* NOTE! Caller must ensure that any side effects from the
27132          * coercions below are safe.  If that cannot be guaranteed
27133          * (which is normally the case), caller must coerce the
27134          * argument using duk_to_number() before any pointer
27135          * validations; the result of duk_to_number() always coerces
27136          * without side effects here.
27137          */
27138
27139         switch (h_bufobj->elem_type) {
27140         case DUK_HBUFOBJ_ELEM_UINT8:
27141                 du.uc[0] = (duk_uint8_t) duk_to_uint32(thr, -1);
27142                 break;
27143         case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
27144                 du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(thr, -1);
27145                 break;
27146         case DUK_HBUFOBJ_ELEM_INT8:
27147                 du.uc[0] = (duk_uint8_t) duk_to_int32(thr, -1);
27148                 break;
27149         case DUK_HBUFOBJ_ELEM_UINT16:
27150                 du.us[0] = (duk_uint16_t) duk_to_uint32(thr, -1);
27151                 break;
27152         case DUK_HBUFOBJ_ELEM_INT16:
27153                 du.us[0] = (duk_uint16_t) duk_to_int32(thr, -1);
27154                 break;
27155         case DUK_HBUFOBJ_ELEM_UINT32:
27156                 du.ui[0] = (duk_uint32_t) duk_to_uint32(thr, -1);
27157                 break;
27158         case DUK_HBUFOBJ_ELEM_INT32:
27159                 du.ui[0] = (duk_uint32_t) duk_to_int32(thr, -1);
27160                 break;
27161         case DUK_HBUFOBJ_ELEM_FLOAT32:
27162                 /* A double-to-float cast is undefined behavior in C99 if
27163                  * the cast is out-of-range, so use a helper.  Example:
27164                  * runtime error: value -1e+100 is outside the range of representable values of type 'float'
27165                  */
27166                 du.f[0] = duk_double_to_float_t(duk_to_number_m1(thr));
27167                 break;
27168         case DUK_HBUFOBJ_ELEM_FLOAT64:
27169                 du.d = (duk_double_t) duk_to_number_m1(thr);
27170                 break;
27171         default:
27172                 DUK_UNREACHABLE();
27173         }
27174
27175         DUK_ASSERT(elem_size > 0);
27176         duk_memcpy((void *) p, (const void *) du.uc, (size_t) elem_size);
27177 }
27178
27179 /* Helper to create a fixed buffer from argument value at index 0.
27180  * Node.js and allocPlain() compatible.
27181  */
27182 DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_hthread *thr) {
27183         duk_int_t len;
27184         duk_int_t i;
27185         duk_size_t buf_size;
27186         duk_uint8_t *buf;
27187
27188         switch (duk_get_type(thr, 0)) {
27189         case DUK_TYPE_NUMBER: {
27190                 len = duk_to_int_clamped(thr, 0, 0, DUK_INT_MAX);
27191                 (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
27192                 break;
27193         }
27194         case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */
27195                 goto slow_copy;
27196         }
27197         case DUK_TYPE_OBJECT: {
27198                 duk_hobject *h;
27199                 duk_hbufobj *h_bufobj;
27200
27201                 /* For Node.js Buffers "Passing an ArrayBuffer returns a Buffer
27202                  * that shares allocated memory with the given ArrayBuffer."
27203                  * https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe
27204                  */
27205
27206                 h = duk_known_hobject(thr, 0);
27207                 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
27208                         DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h));
27209                         h_bufobj = (duk_hbufobj *) h;
27210                         if (DUK_UNLIKELY(h_bufobj->buf == NULL)) {
27211                                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
27212                                 DUK_WO_NORETURN(return NULL;);
27213                         }
27214                         if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) {
27215                                 /* No support for ArrayBuffers with slice
27216                                  * offset/length.
27217                                  */
27218                                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
27219                                 DUK_WO_NORETURN(return NULL;);
27220                         }
27221                         duk_push_hbuffer(thr, h_bufobj->buf);
27222                         return h_bufobj->buf;
27223                 }
27224                 goto slow_copy;
27225         }
27226         case DUK_TYPE_STRING: {
27227                 /* ignore encoding for now */
27228                 duk_require_hstring_notsymbol(thr, 0);
27229                 duk_dup_0(thr);
27230                 (void) duk_to_buffer(thr, -1, &buf_size);
27231                 break;
27232         }
27233         default:
27234                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
27235                 DUK_WO_NORETURN(return NULL;);
27236         }
27237
27238  done:
27239         DUK_ASSERT(duk_is_buffer(thr, -1));
27240         return duk_known_hbuffer(thr, -1);
27241
27242  slow_copy:
27243         /* XXX: fast path for typed arrays and other buffer objects? */
27244
27245         (void) duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LENGTH);
27246         len = duk_to_int_clamped(thr, -1, 0, DUK_INT_MAX);
27247         duk_pop(thr);
27248         buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) len);  /* no zeroing, all indices get initialized */
27249         for (i = 0; i < len; i++) {
27250                 /* XXX: fast path for array or buffer arguments? */
27251                 duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
27252                 buf[i] = (duk_uint8_t) (duk_to_uint32(thr, -1) & 0xffU);
27253                 duk_pop(thr);
27254         }
27255         goto done;
27256 }
27257 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27258
27259 /*
27260  *  Node.js Buffer constructor
27261  *
27262  *  Node.js Buffers are just Uint8Arrays with internal prototype set to
27263  *  Buffer.prototype so they're handled otherwise the same as Uint8Array.
27264  *  However, the constructor arguments are very different so a separate
27265  *  constructor entry point is used.
27266  */
27267 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27268 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_hthread *thr) {
27269         duk_hbuffer *h_buf;
27270
27271         h_buf = duk__hbufobj_fixed_from_argvalue(thr);
27272         DUK_ASSERT(h_buf != NULL);
27273
27274         duk_push_buffer_object(thr,
27275                                -1,
27276                                0,
27277                                DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) (void *) h_buf),
27278                                DUK_BUFOBJ_UINT8ARRAY);
27279         duk_push_hobject_bidx(thr, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
27280         duk_set_prototype(thr, -2);
27281
27282         /* XXX: a more direct implementation */
27283
27284         return 1;
27285 }
27286 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27287
27288 /*
27289  *  ArrayBuffer, DataView, and TypedArray constructors
27290  */
27291
27292 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27293 DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_hthread *thr) {
27294         duk_hbufobj *h_bufobj;
27295         duk_hbuffer *h_val;
27296         duk_int_t len;
27297
27298         DUK_ASSERT_CTX_VALID(thr);
27299
27300         duk_require_constructor_call(thr);
27301
27302         len = duk_to_int(thr, 0);
27303         if (len < 0) {
27304                 goto fail_length;
27305         }
27306         (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) len);
27307         h_val = (duk_hbuffer *) duk_known_hbuffer(thr, -1);
27308
27309         h_bufobj = duk_push_bufobj_raw(thr,
27310                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
27311                                        DUK_HOBJECT_FLAG_BUFOBJ |
27312                                        DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
27313                                        DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
27314         DUK_ASSERT(h_bufobj != NULL);
27315
27316         duk__set_bufobj_buffer(thr, h_bufobj, h_val);
27317         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
27318
27319         return 1;
27320
27321  fail_length:
27322         DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
27323 }
27324 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27325
27326
27327 /* Format of magic, bits:
27328  *   0...1: elem size shift (0-3)
27329  *   2...5: elem type (DUK_HBUFOBJ_ELEM_xxx)
27330  *
27331  * XXX: add prototype bidx explicitly to magic instead of using a mapping?
27332  */
27333
27334 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27335 DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
27336         duk_tval *tv;
27337         duk_hobject *h_obj;
27338         duk_hbufobj *h_bufobj = NULL;
27339         duk_hbufobj *h_bufarg = NULL;
27340         duk_hbuffer *h_val;
27341         duk_small_uint_t magic;
27342         duk_small_uint_t shift;
27343         duk_small_uint_t elem_type;
27344         duk_small_uint_t elem_size;
27345         duk_small_uint_t class_num;
27346         duk_small_uint_t proto_bidx;
27347         duk_uint_t align_mask;
27348         duk_uint_t elem_length;
27349         duk_int_t elem_length_signed;
27350         duk_uint_t byte_length;
27351         duk_small_uint_t copy_mode;
27352
27353         /* XXX: The same copy helpers could be shared with at least some
27354          * buffer functions.
27355          */
27356
27357         duk_require_constructor_call(thr);
27358
27359         /* We could fit built-in index into magic but that'd make the magic
27360          * number dependent on built-in numbering (genbuiltins.py doesn't
27361          * handle that yet).  So map both class and prototype from the
27362          * element type.
27363          */
27364         magic = (duk_small_uint_t) duk_get_current_magic(thr);
27365         shift = magic & 0x03U;               /* bits 0...1: shift */
27366         elem_type = (magic >> 2) & 0x0fU;    /* bits 2...5: type */
27367         elem_size = 1U << shift;
27368         align_mask = elem_size - 1;
27369         DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
27370         proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
27371         DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS);
27372         DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t));
27373         class_num = duk__buffer_class_from_elemtype[elem_type];
27374
27375         DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, "
27376                            "elem_size=%d, proto_bidx=%d, class_num=%d",
27377                            (int) magic, (int) shift, (int) elem_type, (int) elem_size,
27378                            (int) proto_bidx, (int) class_num));
27379
27380         /* Argument variants.  When the argument is an ArrayBuffer a view to
27381          * the same buffer is created; otherwise a new ArrayBuffer is always
27382          * created.
27383          */
27384
27385         /* XXX: initial iteration to treat a plain buffer like an ArrayBuffer:
27386          * coerce to an ArrayBuffer object and use that as .buffer.  The underlying
27387          * buffer will be the same but result .buffer !== inputPlainBuffer.
27388          */
27389         duk_hbufobj_promote_plain(thr, 0);
27390
27391         tv = duk_get_tval(thr, 0);
27392         DUK_ASSERT(tv != NULL);  /* arg count */
27393         if (DUK_TVAL_IS_OBJECT(tv)) {
27394                 h_obj = DUK_TVAL_GET_OBJECT(tv);
27395                 DUK_ASSERT(h_obj != NULL);
27396
27397                 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
27398                         /* ArrayBuffer: unlike any other argument variant, create
27399                          * a view into the existing buffer.
27400                          */
27401
27402                         duk_int_t byte_offset_signed;
27403                         duk_uint_t byte_offset;
27404
27405                         h_bufarg = (duk_hbufobj *) h_obj;
27406
27407                         byte_offset_signed = duk_to_int(thr, 1);
27408                         if (byte_offset_signed < 0) {
27409                                 goto fail_arguments;
27410                         }
27411                         byte_offset = (duk_uint_t) byte_offset_signed;
27412                         if (byte_offset > h_bufarg->length ||
27413                             (byte_offset & align_mask) != 0) {
27414                                 /* Must be >= 0 and multiple of element size. */
27415                                 goto fail_arguments;
27416                         }
27417                         if (duk_is_undefined(thr, 2)) {
27418                                 DUK_ASSERT(h_bufarg->length >= byte_offset);
27419                                 byte_length = h_bufarg->length - byte_offset;
27420                                 if ((byte_length & align_mask) != 0) {
27421                                         /* Must be element size multiple from
27422                                          * start offset to end of buffer.
27423                                          */
27424                                         goto fail_arguments;
27425                                 }
27426                                 elem_length = (byte_length >> shift);
27427                         } else {
27428                                 elem_length_signed = duk_to_int(thr, 2);
27429                                 if (elem_length_signed < 0) {
27430                                         goto fail_arguments;
27431                                 }
27432                                 elem_length = (duk_uint_t) elem_length_signed;
27433                                 byte_length = elem_length << shift;
27434                                 if ((byte_length >> shift) != elem_length) {
27435                                         /* Byte length would overflow. */
27436                                         /* XXX: easier check with less code? */
27437                                         goto fail_arguments;
27438                                 }
27439                                 DUK_ASSERT(h_bufarg->length >= byte_offset);
27440                                 if (byte_length > h_bufarg->length - byte_offset) {
27441                                         /* Not enough data. */
27442                                         goto fail_arguments;
27443                                 }
27444                         }
27445                         DUK_UNREF(elem_length);
27446                         DUK_ASSERT_DISABLE(byte_offset >= 0);
27447                         DUK_ASSERT(byte_offset <= h_bufarg->length);
27448                         DUK_ASSERT_DISABLE(byte_length >= 0);
27449                         DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
27450                         DUK_ASSERT((elem_length << shift) == byte_length);
27451
27452                         h_bufobj = duk_push_bufobj_raw(thr,
27453                                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
27454                                                        DUK_HOBJECT_FLAG_BUFOBJ |
27455                                                        DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
27456                                                        (duk_small_int_t) proto_bidx);
27457                         h_val = h_bufarg->buf;
27458                         if (h_val == NULL) {
27459                                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27460                         }
27461                         h_bufobj->buf = h_val;
27462                         DUK_HBUFFER_INCREF(thr, h_val);
27463                         h_bufobj->offset = h_bufarg->offset + byte_offset;
27464                         h_bufobj->length = byte_length;
27465                         h_bufobj->shift = (duk_uint8_t) shift;
27466                         h_bufobj->elem_type = (duk_uint8_t) elem_type;
27467                         h_bufobj->is_typedarray = 1;
27468                         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
27469
27470                         /* Set .buffer to the argument ArrayBuffer. */
27471                         DUK_ASSERT(h_bufobj->buf_prop == NULL);
27472                         h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
27473                         DUK_ASSERT(h_bufarg != NULL);
27474                         DUK_HBUFOBJ_INCREF(thr, h_bufarg);
27475                         return 1;
27476                 } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
27477                         /* TypedArray (or other non-ArrayBuffer duk_hbufobj).
27478                          * Conceptually same behavior as for an Array-like argument,
27479                          * with a few fast paths.
27480                          */
27481
27482                         h_bufarg = (duk_hbufobj *) h_obj;
27483                         DUK_ASSERT_HBUFOBJ_VALID(h_bufarg);
27484                         elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift);
27485                         if (h_bufarg->buf == NULL) {
27486                                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27487                         }
27488
27489                         /* Select copy mode.  Must take into account element
27490                          * compatibility and validity of the underlying source
27491                          * buffer.
27492                          */
27493
27494                         DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, "
27495                                              "src byte_length=%ld, src shift=%d, "
27496                                              "src/dst elem_length=%ld; "
27497                                              "dst shift=%d -> dst byte_length=%ld",
27498                                              (long) h_bufarg->length, (int) h_bufarg->shift,
27499                                              (long) elem_length_signed, (int) shift,
27500                                              (long) (elem_length_signed << shift)));
27501
27502                         copy_mode = 2;  /* default is explicit index read/write copy */
27503 #if !defined(DUK_USE_PREFER_SIZE)
27504                         /* With a size optimized build copy_mode 2 is enough.
27505                          * Modes 0 and 1 are faster but conceptually the same.
27506                          */
27507                         DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
27508                         if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
27509                                 if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) {
27510                                         DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy"));
27511                                         DUK_ASSERT(shift == h_bufarg->shift);  /* byte sizes will match */
27512                                         copy_mode = 0;
27513                                 } else {
27514                                         DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy"));
27515                                         copy_mode = 1;
27516                                 }
27517                         }
27518 #endif  /* !DUK_USE_PREFER_SIZE */
27519                 } else {
27520                         /* Array or Array-like */
27521                         elem_length_signed = (duk_int_t) duk_get_length(thr, 0);
27522                         copy_mode = 2;
27523                 }
27524         } else {
27525                 /* Non-object argument is simply int coerced, matches
27526                  * V8 behavior (except for "null", which we coerce to
27527                  * 0 but V8 TypeErrors).
27528                  */
27529                 elem_length_signed = duk_to_int(thr, 0);
27530                 copy_mode = 3;
27531         }
27532         if (elem_length_signed < 0) {
27533                 goto fail_arguments;
27534         }
27535         elem_length = (duk_uint_t) elem_length_signed;
27536         byte_length = (duk_uint_t) (elem_length << shift);
27537         if ((byte_length >> shift) != elem_length) {
27538                 /* Byte length would overflow. */
27539                 /* XXX: easier check with less code? */
27540                 goto fail_arguments;
27541         }
27542
27543         DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld",
27544                              (long) elem_length, (long) byte_length));
27545
27546         /* ArrayBuffer argument is handled specially above; the rest of the
27547          * argument variants are handled by shared code below.
27548          *
27549          * ArrayBuffer in h_bufobj->buf_prop is intentionally left unset.
27550          * It will be automatically created by the .buffer accessor on
27551          * first access.
27552          */
27553
27554         /* Push the resulting view object on top of a plain fixed buffer. */
27555         (void) duk_push_fixed_buffer(thr, byte_length);
27556         h_val = duk_known_hbuffer(thr, -1);
27557         DUK_ASSERT(h_val != NULL);
27558
27559         h_bufobj = duk_push_bufobj_raw(thr,
27560                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
27561                                        DUK_HOBJECT_FLAG_BUFOBJ |
27562                                        DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
27563                                        (duk_small_int_t) proto_bidx);
27564
27565         h_bufobj->buf = h_val;
27566         DUK_HBUFFER_INCREF(thr, h_val);
27567         DUK_ASSERT(h_bufobj->offset == 0);
27568         h_bufobj->length = byte_length;
27569         h_bufobj->shift = (duk_uint8_t) shift;
27570         h_bufobj->elem_type = (duk_uint8_t) elem_type;
27571         h_bufobj->is_typedarray = 1;
27572         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
27573
27574         /* Copy values, the copy method depends on the arguments.
27575          *
27576          * Copy mode decision may depend on the validity of the underlying
27577          * buffer of the source argument; there must be no harmful side effects
27578          * from there to here for copy_mode to still be valid.
27579          */
27580         DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode));
27581         switch (copy_mode) {
27582                 /* Copy modes 0 and 1 can be omitted in size optimized build,
27583                  * copy mode 2 handles them (but more slowly).
27584                  */
27585 #if !defined(DUK_USE_PREFER_SIZE)
27586         case 0: {
27587                 /* Use byte copy. */
27588
27589                 duk_uint8_t *p_src;
27590                 duk_uint8_t *p_dst;
27591
27592                 DUK_ASSERT(h_bufobj != NULL);
27593                 DUK_ASSERT(h_bufobj->buf != NULL);
27594                 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
27595                 DUK_ASSERT(h_bufarg != NULL);
27596                 DUK_ASSERT(h_bufarg->buf != NULL);
27597                 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
27598
27599                 p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
27600                 p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
27601
27602                 DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
27603                                      (void *) p_src, (void *) p_dst, (long) byte_length));
27604
27605                 duk_memcpy_unsafe((void *) p_dst, (const void *) p_src, (size_t) byte_length);
27606                 break;
27607         }
27608         case 1: {
27609                 /* Copy values through direct validated reads and writes. */
27610
27611                 duk_small_uint_t src_elem_size;
27612                 duk_small_uint_t dst_elem_size;
27613                 duk_uint8_t *p_src;
27614                 duk_uint8_t *p_src_end;
27615                 duk_uint8_t *p_dst;
27616
27617                 DUK_ASSERT(h_bufobj != NULL);
27618                 DUK_ASSERT(h_bufobj->buf != NULL);
27619                 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
27620                 DUK_ASSERT(h_bufarg != NULL);
27621                 DUK_ASSERT(h_bufarg->buf != NULL);
27622                 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
27623
27624                 src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
27625                 dst_elem_size = elem_size;
27626
27627                 p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
27628                 p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
27629                 p_src_end = p_src + h_bufarg->length;
27630
27631                 DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, "
27632                                      "src_elem_size=%d, dst_elem_size=%d",
27633                                      (void *) p_src, (void *) p_src_end, (void *) p_dst,
27634                                      (int) src_elem_size, (int) dst_elem_size));
27635
27636                 while (p_src != p_src_end) {
27637                         DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
27638                                              "p_src=%p, p_src_end=%p, p_dst=%p",
27639                                              (void *) p_src, (void *) p_src_end, (void *) p_dst));
27640                         /* A validated read() is always a number, so it's write coercion
27641                          * is always side effect free an won't invalidate pointers etc.
27642                          */
27643                         duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
27644                         duk_hbufobj_validated_write(thr, h_bufobj, p_dst, dst_elem_size);
27645                         duk_pop(thr);
27646                         p_src += src_elem_size;
27647                         p_dst += dst_elem_size;
27648                 }
27649                 break;
27650         }
27651 #endif  /* !DUK_USE_PREFER_SIZE */
27652         case 2: {
27653                 /* Copy values by index reads and writes.  Let virtual
27654                  * property handling take care of coercion.
27655                  */
27656                 duk_uint_t i;
27657
27658                 DUK_DDD(DUK_DDDPRINT("using slow copy"));
27659
27660                 for (i = 0; i < elem_length; i++) {
27661                         duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
27662                         duk_put_prop_index(thr, -2, (duk_uarridx_t) i);
27663                 }
27664                 break;
27665         }
27666         default:
27667         case 3: {
27668                 /* No copy, leave zero bytes in the buffer.  There's no
27669                  * ambiguity with Float32/Float64 because zero bytes also
27670                  * represent 0.0.
27671                  */
27672
27673                 DUK_DDD(DUK_DDDPRINT("using no copy"));
27674                 break;
27675         }
27676         }
27677
27678         return 1;
27679
27680  fail_arguments:
27681         DUK_DCERROR_RANGE_INVALID_ARGS(thr);
27682 }
27683 #else  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27684 /* When bufferobject support is disabled, new Uint8Array() could still be
27685  * supported to create a plain fixed buffer.  Disabled for now.
27686  */
27687 #if 0
27688 DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_hthread *thr) {
27689         duk_int_t elem_length_signed;
27690         duk_uint_t byte_length;
27691
27692         /* XXX: The same copy helpers could be shared with at least some
27693          * buffer functions.
27694          */
27695
27696         duk_require_constructor_call(thr);
27697
27698         elem_length_signed = duk_require_int(thr, 0);
27699         if (elem_length_signed < 0) {
27700                 goto fail_arguments;
27701         }
27702         byte_length = (duk_uint_t) elem_length_signed;
27703
27704         (void) duk_push_fixed_buffer_zero(thr, (duk_size_t) byte_length);
27705         return 1;
27706
27707  fail_arguments:
27708         DUK_DCERROR_RANGE_INVALID_ARGS(thr);
27709 }
27710 #endif  /* 0 */
27711 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27712
27713 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27714 DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_hthread *thr) {
27715         duk_hbufobj *h_bufarg;
27716         duk_hbufobj *h_bufobj;
27717         duk_hbuffer *h_val;
27718         duk_uint_t offset;
27719         duk_uint_t length;
27720
27721         duk_require_constructor_call(thr);
27722
27723         h_bufarg = duk__require_bufobj_value(thr, 0);
27724         DUK_ASSERT(h_bufarg != NULL);
27725         if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
27726                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27727         }
27728
27729         duk__resolve_offset_opt_length(thr, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
27730         DUK_ASSERT(offset <= h_bufarg->length);
27731         DUK_ASSERT(offset + length <= h_bufarg->length);
27732
27733         h_bufobj = duk_push_bufobj_raw(thr,
27734                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
27735                                        DUK_HOBJECT_FLAG_BUFOBJ |
27736                                        DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
27737                                        DUK_BIDX_DATAVIEW_PROTOTYPE);
27738
27739         h_val = h_bufarg->buf;
27740         if (h_val == NULL) {
27741                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27742         }
27743         h_bufobj->buf = h_val;
27744         DUK_HBUFFER_INCREF(thr, h_val);
27745         h_bufobj->offset = h_bufarg->offset + offset;
27746         h_bufobj->length = length;
27747         DUK_ASSERT(h_bufobj->shift == 0);
27748         DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
27749         DUK_ASSERT(h_bufobj->is_typedarray == 0);
27750
27751         DUK_ASSERT(h_bufobj->buf_prop == NULL);
27752         h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
27753         DUK_ASSERT(h_bufarg != NULL);
27754         DUK_HBUFOBJ_INCREF(thr, h_bufarg);
27755
27756         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
27757         return 1;
27758 }
27759 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27760
27761 /*
27762  *  ArrayBuffer.isView()
27763  */
27764
27765 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27766 DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_hthread *thr) {
27767         duk_hobject *h_obj;
27768         duk_bool_t ret = 0;
27769
27770         if (duk_is_buffer(thr, 0)) {
27771                 ret = 1;
27772         } else {
27773                 h_obj = duk_get_hobject(thr, 0);
27774                 if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
27775                         /* DataView needs special casing: ArrayBuffer.isView() is
27776                          * true, but ->is_typedarray is 0.
27777                          */
27778                         ret = ((duk_hbufobj *) h_obj)->is_typedarray ||
27779                               (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW);
27780                 }
27781         }
27782         duk_push_boolean(thr, ret);
27783         return 1;
27784 }
27785 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27786
27787 /*
27788  *  Uint8Array.allocPlain()
27789  */
27790
27791 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27792 DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_hthread *thr) {
27793         duk__hbufobj_fixed_from_argvalue(thr);
27794         return 1;
27795 }
27796 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27797
27798 /*
27799  *  Uint8Array.plainOf()
27800  */
27801
27802 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27803 DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_hthread *thr) {
27804         duk_hbufobj *h_bufobj;
27805
27806 #if !defined(DUK_USE_PREFER_SIZE)
27807         /* Avoid churn if argument is already a plain buffer. */
27808         if (duk_is_buffer(thr, 0)) {
27809                 return 1;
27810         }
27811 #endif
27812
27813         /* Promotes plain buffers to ArrayBuffers, so for a plain buffer
27814          * argument we'll create a pointless temporary (but still work
27815          * correctly).
27816          */
27817         h_bufobj = duk__require_bufobj_value(thr, 0);
27818         if (h_bufobj->buf == NULL) {
27819                 duk_push_undefined(thr);
27820         } else {
27821                 duk_push_hbuffer(thr, h_bufobj->buf);
27822         }
27823         return 1;
27824 }
27825 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27826
27827 /*
27828  *  Node.js Buffer: toString([encoding], [start], [end])
27829  */
27830
27831 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27832 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_hthread *thr) {
27833         duk_hbufobj *h_this;
27834         duk_int_t start_offset, end_offset;
27835         duk_uint8_t *buf_slice;
27836         duk_size_t slice_length;
27837
27838         h_this = duk__get_bufobj_this(thr);
27839         if (h_this == NULL) {
27840                 /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
27841                 duk_push_literal(thr, "[object Object]");
27842                 return 1;
27843         }
27844         DUK_ASSERT_HBUFOBJ_VALID(h_this);
27845
27846         /* Ignore encoding for now. */
27847
27848         duk__clamp_startend_nonegidx_noshift(thr,
27849                                              (duk_int_t) h_this->length,
27850                                              1 /*idx_start*/,
27851                                              2 /*idx_end*/,
27852                                              &start_offset,
27853                                              &end_offset);
27854
27855         slice_length = (duk_size_t) (end_offset - start_offset);
27856         buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, slice_length);  /* all bytes initialized below */
27857         DUK_ASSERT(buf_slice != NULL);
27858
27859         /* Neutered or uncovered, TypeError. */
27860         if (h_this->buf == NULL ||
27861             !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length)) {
27862                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
27863         }
27864
27865         /* XXX: ideally we wouldn't make a copy but a view into the buffer for the
27866          * decoding process.  Or the decoding helper could be changed to accept
27867          * the slice info (a buffer pointer is NOT a good approach because guaranteeing
27868          * its stability is difficult).
27869          */
27870
27871         DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, (duk_size_t) start_offset + slice_length));
27872         duk_memcpy_unsafe((void *) buf_slice,
27873                           (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
27874                           (size_t) slice_length);
27875
27876         /* Use the equivalent of: new TextEncoder().encode(this) to convert the
27877          * string.  Result will be valid UTF-8; non-CESU-8 inputs are currently
27878          * interpreted loosely.  Value stack convention is a bit odd for now.
27879          */
27880         duk_replace(thr, 0);
27881         duk_set_top(thr, 1);
27882         return duk_textdecoder_decode_utf8_nodejs(thr);
27883 }
27884 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27885
27886 /*
27887  *  Node.js Buffer.prototype: toJSON()
27888  */
27889
27890 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27891 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_hthread *thr) {
27892         duk_hbufobj *h_this;
27893         duk_uint8_t *buf;
27894         duk_uint_t i, n;
27895         duk_tval *tv;
27896
27897         h_this = duk__require_bufobj_this(thr);
27898         DUK_ASSERT(h_this != NULL);
27899
27900         if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) {
27901                 /* Serialize uncovered backing buffer as a null; doesn't
27902                  * really matter as long we're memory safe.
27903                  */
27904                 duk_push_null(thr);
27905                 return 1;
27906         }
27907
27908         duk_push_object(thr);
27909         duk_push_hstring_stridx(thr, DUK_STRIDX_UC_BUFFER);
27910         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_TYPE);
27911
27912         /* XXX: uninitialized would be OK */
27913         DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX);
27914         tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) h_this->length);  /* XXX: needs revision with >4G buffers */
27915
27916         DUK_ASSERT(h_this->buf != NULL);
27917         buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
27918         for (i = 0, n = h_this->length; i < n; i++) {
27919                 DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]);  /* no need for decref or incref */
27920         }
27921         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_DATA);
27922
27923         return 1;
27924 }
27925 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27926
27927 /*
27928  *  Node.js Buffer.prototype.equals()
27929  *  Node.js Buffer.prototype.compare()
27930  *  Node.js Buffer.compare()
27931  */
27932
27933 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27934 DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_hthread *thr) {
27935         duk_small_uint_t magic;
27936         duk_hbufobj *h_bufarg1;
27937         duk_hbufobj *h_bufarg2;
27938         duk_small_int_t comp_res;
27939
27940         /* XXX: keep support for plain buffers and non-Node.js buffers? */
27941
27942         magic = (duk_small_uint_t) duk_get_current_magic(thr);
27943         if (magic & 0x02U) {
27944                 /* Static call style. */
27945                 h_bufarg1 = duk__require_bufobj_value(thr, 0);
27946                 h_bufarg2 = duk__require_bufobj_value(thr, 1);
27947         } else {
27948                 h_bufarg1 = duk__require_bufobj_this(thr);
27949                 h_bufarg2 = duk__require_bufobj_value(thr, 0);
27950         }
27951         DUK_ASSERT(h_bufarg1 != NULL);
27952         DUK_ASSERT(h_bufarg2 != NULL);
27953
27954         /* We want to compare the slice/view areas of the arguments.
27955          * If either slice/view is invalid (underlying buffer is shorter)
27956          * ensure equals() is false, but otherwise the only thing that
27957          * matters is to be memory safe.
27958          */
27959
27960         if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg1) &&
27961             DUK_HBUFOBJ_VALID_SLICE(h_bufarg2)) {
27962                 comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset,
27963                                                (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset,
27964                                                (duk_size_t) h_bufarg1->length,
27965                                                (duk_size_t) h_bufarg2->length);
27966         } else {
27967                 comp_res = -1;  /* either nonzero value is ok */
27968         }
27969
27970         if (magic & 0x01U) {
27971                 /* compare: similar to string comparison but for buffer data. */
27972                 duk_push_int(thr, comp_res);
27973         } else {
27974                 /* equals */
27975                 duk_push_boolean(thr, (comp_res == 0));
27976         }
27977
27978         return 1;
27979 }
27980 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
27981
27982 /*
27983  *  Node.js Buffer.prototype.fill()
27984  */
27985
27986 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
27987 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_hthread *thr) {
27988         duk_hbufobj *h_this;
27989         const duk_uint8_t *fill_str_ptr;
27990         duk_size_t fill_str_len;
27991         duk_uint8_t fill_value;
27992         duk_int_t fill_offset;
27993         duk_int_t fill_end;
27994         duk_size_t fill_length;
27995         duk_uint8_t *p;
27996
27997         h_this = duk__require_bufobj_this(thr);
27998         DUK_ASSERT(h_this != NULL);
27999         if (h_this->buf == NULL) {
28000                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28001         }
28002
28003         /* [ value offset end ] */
28004
28005         if (duk_is_string_notsymbol(thr, 0)) {
28006                 fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(thr, 0, &fill_str_len);
28007                 DUK_ASSERT(fill_str_ptr != NULL);
28008         } else {
28009                 /* Symbols get ToNumber() coerced and cause TypeError. */
28010                 fill_value = (duk_uint8_t) duk_to_uint32(thr, 0);
28011                 fill_str_ptr = (const duk_uint8_t *) &fill_value;
28012                 fill_str_len = 1;
28013         }
28014
28015         /* Fill offset handling is more lenient than in Node.js. */
28016
28017         duk__clamp_startend_nonegidx_noshift(thr,
28018                                              (duk_int_t) h_this->length,
28019                                              1 /*idx_start*/,
28020                                              2 /*idx_end*/,
28021                                              &fill_offset,
28022                                              &fill_end);
28023
28024         DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld",
28025                              (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length));
28026
28027         DUK_ASSERT(fill_end - fill_offset >= 0);
28028         DUK_ASSERT(h_this->buf != NULL);
28029
28030         p = (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
28031         fill_length = (duk_size_t) (fill_end - fill_offset);
28032         if (fill_str_len == 1) {
28033                 /* Handle single character fills as memset() even when
28034                  * the fill data comes from a one-char argument.
28035                  */
28036                 duk_memset_unsafe((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
28037         } else if (fill_str_len > 1) {
28038                 duk_size_t i, n, t;
28039
28040                 for (i = 0, n = (duk_size_t) (fill_end - fill_offset), t = 0; i < n; i++) {
28041                         p[i] = fill_str_ptr[t++];
28042                         if (t >= fill_str_len) {
28043                                 t = 0;
28044                         }
28045                 }
28046         } else {
28047                 DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently"));
28048         }
28049
28050         /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
28051         duk_push_this(thr);
28052         return 1;
28053 }
28054 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28055
28056 /*
28057  *  Node.js Buffer.prototype.write(string, [offset], [length], [encoding])
28058  */
28059
28060 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28061 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_hthread *thr) {
28062         duk_hbufobj *h_this;
28063         duk_uint_t offset;
28064         duk_uint_t length;
28065         const duk_uint8_t *str_data;
28066         duk_size_t str_len;
28067
28068         /* XXX: very inefficient support for plain buffers */
28069         h_this = duk__require_bufobj_this(thr);
28070         DUK_ASSERT(h_this != NULL);
28071
28072         /* Argument must be a string, e.g. a buffer is not allowed. */
28073         str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(thr, 0, &str_len);
28074
28075         duk__resolve_offset_opt_length(thr, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
28076         DUK_ASSERT(offset <= h_this->length);
28077         DUK_ASSERT(offset + length <= h_this->length);
28078
28079         /* XXX: encoding is ignored now. */
28080
28081         if (length > str_len) {
28082                 length = (duk_uint_t) str_len;
28083         }
28084
28085         if (DUK_HBUFOBJ_VALID_SLICE(h_this)) {
28086                 /* Cannot overlap. */
28087                 duk_memcpy_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
28088                                   (const void *) str_data,
28089                                   (size_t) length);
28090         } else {
28091                 DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
28092         }
28093
28094         duk_push_uint(thr, length);
28095         return 1;
28096 }
28097 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28098
28099 /*
28100  *  Node.js Buffer.prototype.copy()
28101  */
28102
28103 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28104 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_hthread *thr) {
28105         duk_hbufobj *h_this;
28106         duk_hbufobj *h_bufarg;
28107         duk_int_t source_length;
28108         duk_int_t target_length;
28109         duk_int_t target_start, source_start, source_end;
28110         duk_uint_t target_ustart, source_ustart, source_uend;
28111         duk_uint_t copy_size = 0;
28112
28113         /* [ targetBuffer targetStart sourceStart sourceEnd ] */
28114
28115         h_this = duk__require_bufobj_this(thr);
28116         h_bufarg = duk__require_bufobj_value(thr, 0);
28117         DUK_ASSERT(h_this != NULL);
28118         DUK_ASSERT(h_bufarg != NULL);
28119         source_length = (duk_int_t) h_this->length;
28120         target_length = (duk_int_t) h_bufarg->length;
28121
28122         target_start = duk_to_int(thr, 1);
28123         source_start = duk_to_int(thr, 2);
28124         if (duk_is_undefined(thr, 3)) {
28125                 source_end = source_length;
28126         } else {
28127                 source_end = duk_to_int(thr, 3);
28128         }
28129
28130         DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
28131                              "source_start=%ld, source_end=%ld, source_length=%ld",
28132                              (long) target_start, (long) h_bufarg->length,
28133                              (long) source_start, (long) source_end, (long) source_length));
28134
28135         /* This behavior mostly mimics Node.js now. */
28136
28137         if (source_start < 0 || source_end < 0 || target_start < 0) {
28138                 /* Negative offsets cause a RangeError. */
28139                 goto fail_bounds;
28140         }
28141         source_ustart = (duk_uint_t) source_start;
28142         source_uend = (duk_uint_t) source_end;
28143         target_ustart = (duk_uint_t) target_start;
28144         if (source_ustart >= source_uend ||  /* crossed offsets or zero size */
28145             source_ustart >= (duk_uint_t) source_length ||  /* source out-of-bounds (but positive) */
28146             target_ustart >= (duk_uint_t) target_length) {  /* target out-of-bounds (but positive) */
28147                 goto silent_ignore;
28148         }
28149         if (source_uend >= (duk_uint_t) source_length) {
28150                 /* Source end clamped silently to available length. */
28151                 source_uend = (duk_uint_t) source_length;
28152         }
28153         copy_size = source_uend - source_ustart;
28154         if (target_ustart + copy_size > (duk_uint_t) target_length) {
28155                 /* Clamp to target's end if too long.
28156                  *
28157                  * NOTE: there's no overflow possibility in the comparison;
28158                  * both target_ustart and copy_size are >= 0 and based on
28159                  * values in duk_int_t range.  Adding them as duk_uint_t
28160                  * values is then guaranteed not to overflow.
28161                  */
28162                 DUK_ASSERT(target_ustart + copy_size >= target_ustart);  /* no overflow */
28163                 DUK_ASSERT(target_ustart + copy_size >= copy_size);  /* no overflow */
28164                 copy_size = (duk_uint_t) target_length - target_ustart;
28165         }
28166
28167         DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu",
28168                              (unsigned long) target_ustart, (unsigned long) source_ustart,
28169                              (unsigned long) copy_size));
28170
28171         DUK_ASSERT(copy_size >= 1);
28172         DUK_ASSERT(source_ustart <= (duk_uint_t) source_length);
28173         DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length);
28174         DUK_ASSERT(target_ustart <= (duk_uint_t) target_length);
28175         DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length);
28176
28177         /* Ensure copy is covered by underlying buffers. */
28178         DUK_ASSERT(h_bufarg->buf != NULL);  /* length check */
28179         DUK_ASSERT(h_this->buf != NULL);    /* length check */
28180         if (DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
28181             DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
28182                 /* Must use memmove() because copy area may overlap (source and target
28183                  * buffer may be the same, or from different slices.
28184                  */
28185                 duk_memmove_unsafe((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
28186                                    (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
28187                                    (size_t) copy_size);
28188         } else {
28189                 DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
28190         }
28191
28192  silent_ignore:
28193         /* Return value is like write(), number of bytes written.
28194          * The return value matters because of code like:
28195          * "off += buf.copy(...)".
28196          */
28197         duk_push_uint(thr, copy_size);
28198         return 1;
28199
28200  fail_bounds:
28201         DUK_DCERROR_RANGE_INVALID_ARGS(thr);
28202 }
28203 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28204
28205 /*
28206  *  TypedArray.prototype.set()
28207  *
28208  *  TypedArray set() is pretty interesting to implement because:
28209  *
28210  *    - The source argument may be a plain array or a typedarray.  If the
28211  *      source is a TypedArray, values are decoded and re-encoded into the
28212  *      target (not as a plain byte copy).  This may happen even when the
28213  *      element byte size is the same, e.g. integer values may be re-encoded
28214  *      into floats.
28215  *
28216  *    - Source and target may refer to the same underlying buffer, so that
28217  *      the set() operation may overlap.  The specification requires that this
28218  *      must work as if a copy was made before the operation.  Note that this
28219  *      is NOT a simple memmove() situation because the source and target
28220  *      byte sizes may be different -- e.g. a 4-byte source (Int8Array) may
28221  *      expand to a 16-byte target (Uint32Array) so that the target overlaps
28222  *      the source both from beginning and the end (unlike in typical memmove).
28223  *
28224  *    - Even if 'buf' pointers of the source and target differ, there's no
28225  *      guarantee that their memory areas don't overlap.  This may be the
28226  *      case with external buffers.
28227  *
28228  *  Even so, it is nice to optimize for the common case:
28229  *
28230  *    - Source and target separate buffers or non-overlapping.
28231  *
28232  *    - Source and target have a compatible type so that a plain byte copy
28233  *      is possible.  Note that while e.g. uint8 and int8 are compatible
28234  *      (coercion one way or another doesn't change the byte representation),
28235  *      e.g. int8 and uint8clamped are NOT compatible when writing int8
28236  *      values into uint8clamped typedarray (-1 would clamp to 0 for instance).
28237  *
28238  *  See test-bi-typedarray-proto-set.js.
28239  */
28240
28241 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28242 DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_hthread *thr) {
28243         duk_hbufobj *h_this;
28244         duk_hobject *h_obj;
28245         duk_uarridx_t i, n;
28246         duk_int_t offset_signed;
28247         duk_uint_t offset_elems;
28248         duk_uint_t offset_bytes;
28249
28250         h_this = duk__require_bufobj_this(thr);
28251         DUK_ASSERT(h_this != NULL);
28252         DUK_ASSERT_HBUFOBJ_VALID(h_this);
28253
28254         if (h_this->buf == NULL) {
28255                 DUK_DDD(DUK_DDDPRINT("source neutered, skip copy"));
28256                 return 0;
28257         }
28258
28259         duk_hbufobj_promote_plain(thr, 0);
28260         h_obj = duk_require_hobject(thr, 0);
28261
28262         /* XXX: V8 throws a TypeError for negative values.  Would it
28263          * be more useful to interpret negative offsets here from the
28264          * end of the buffer too?
28265          */
28266         offset_signed = duk_to_int(thr, 1);
28267         if (offset_signed < 0) {
28268                 /* For some reason this is a TypeError (at least in V8). */
28269                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28270         }
28271         offset_elems = (duk_uint_t) offset_signed;
28272         offset_bytes = offset_elems << h_this->shift;
28273         if ((offset_bytes >> h_this->shift) != offset_elems) {
28274                 /* Byte length would overflow. */
28275                 /* XXX: easier check with less code? */
28276                 goto fail_args;
28277         }
28278         if (offset_bytes > h_this->length) {
28279                 /* Equality may be OK but >length not.  Checking
28280                  * this explicitly avoids some overflow cases
28281                  * below.
28282                  */
28283                 goto fail_args;
28284         }
28285         DUK_ASSERT(offset_bytes <= h_this->length);
28286
28287         /* Fast path: source is a TypedArray (or any bufobj). */
28288
28289         if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
28290                 duk_hbufobj *h_bufarg;
28291 #if !defined(DUK_USE_PREFER_SIZE)
28292                 duk_uint16_t comp_mask;
28293 #endif
28294                 duk_small_int_t no_overlap = 0;
28295                 duk_uint_t src_length;
28296                 duk_uint_t dst_length;
28297                 duk_uint_t dst_length_elems;
28298                 duk_uint8_t *p_src_base;
28299                 duk_uint8_t *p_src_end;
28300                 duk_uint8_t *p_src;
28301                 duk_uint8_t *p_dst_base;
28302                 duk_uint8_t *p_dst;
28303                 duk_small_uint_t src_elem_size;
28304                 duk_small_uint_t dst_elem_size;
28305
28306                 h_bufarg = (duk_hbufobj *) h_obj;
28307                 DUK_ASSERT_HBUFOBJ_VALID(h_bufarg);
28308
28309                 if (h_bufarg->buf == NULL) {
28310                         DUK_DDD(DUK_DDDPRINT("target neutered, skip copy"));
28311                         return 0;
28312                 }
28313
28314                 /* Nominal size check. */
28315                 src_length = h_bufarg->length;  /* bytes in source */
28316                 dst_length_elems = (src_length >> h_bufarg->shift);  /* elems in source and dest */
28317                 dst_length = dst_length_elems << h_this->shift;  /* bytes in dest */
28318                 if ((dst_length >> h_this->shift) != dst_length_elems) {
28319                         /* Byte length would overflow. */
28320                         /* XXX: easier check with less code? */
28321                         goto fail_args;
28322                 }
28323                 DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld",
28324                                      (long) src_length, (long) dst_length));
28325                 DUK_ASSERT(offset_bytes <= h_this->length);
28326                 if (dst_length > h_this->length - offset_bytes) {
28327                         /* Overflow not an issue because subtraction is used on the right
28328                          * side and guaranteed to be >= 0.
28329                          */
28330                         DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
28331                         goto fail_args;
28332                 }
28333                 if (!DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
28334                         DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore"));
28335                         return 0;
28336                 }
28337
28338                 p_src_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
28339                 p_dst_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
28340
28341                 /* Check actual underlying buffers for validity and that they
28342                  * cover the copy.  No side effects are allowed after the check
28343                  * so that the validity status doesn't change.
28344                  */
28345                 if (!DUK_HBUFOBJ_VALID_SLICE(h_this) ||
28346                     !DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
28347                         /* The condition could be more narrow and check for the
28348                          * copy area only, but there's no need for fine grained
28349                          * behavior when the underlying buffer is misconfigured.
28350                          */
28351                         DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy"));
28352                         return 0;
28353                 }
28354
28355                 /* We want to do a straight memory copy if possible: this is
28356                  * an important operation because .set() is the TypedArray
28357                  * way to copy chunks of memory.  However, because set()
28358                  * conceptually works in terms of elements, not all views are
28359                  * compatible with direct byte copying.
28360                  *
28361                  * If we do manage a direct copy, the "overlap issue" handled
28362                  * below can just be solved using memmove() because the source
28363                  * and destination element sizes are necessarily equal.
28364                  */
28365
28366 #if !defined(DUK_USE_PREFER_SIZE)
28367                 DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
28368                 comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type];
28369                 if (comp_mask & (1 << h_bufarg->elem_type)) {
28370                         DUK_ASSERT(src_length == dst_length);
28371
28372                         DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible"));
28373                         duk_memmove_unsafe((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
28374                         return 0;
28375                 }
28376                 DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
28377 #endif  /* !DUK_USE_PREFER_SIZE */
28378
28379                 /* We want to avoid making a copy to process set() but that's
28380                  * not always possible: the source and the target may overlap
28381                  * and because element sizes are different, the overlap cannot
28382                  * always be handled with a memmove() or choosing the copy
28383                  * direction in a certain way.  For example, if source type is
28384                  * uint8 and target type is uint32, the target area may exceed
28385                  * the source area from both ends!
28386                  *
28387                  * Note that because external buffers may point to the same
28388                  * memory areas, we must ultimately make this check using
28389                  * pointers.
28390                  *
28391                  * NOTE: careful with side effects: any side effect may cause
28392                  * a buffer resize (or external buffer pointer/length update)!
28393                  */
28394
28395                 DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, "
28396                                      "p_dst_base=%p, dst_length=%ld",
28397                                      (void *) p_src_base, (long) src_length,
28398                                      (void *) p_dst_base, (long) dst_length));
28399
28400                 if (p_src_base >= p_dst_base + dst_length ||  /* source starts after dest ends */
28401                     p_src_base + src_length <= p_dst_base) {   /* source ends before dest starts */
28402                         no_overlap = 1;
28403                 }
28404
28405                 if (!no_overlap) {
28406                         /* There's overlap: the desired end result is that
28407                          * conceptually a copy is made to avoid "trampling"
28408                          * of source data by destination writes.  We make
28409                          * an actual temporary copy to handle this case.
28410                          */
28411                         duk_uint8_t *p_src_copy;
28412
28413                         DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
28414                         p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_length);
28415                         DUK_ASSERT(p_src_copy != NULL);
28416                         duk_memcpy_unsafe((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
28417
28418                         p_src_base = p_src_copy;  /* use p_src_base from now on */
28419                 }
28420                 /* Value stack intentionally mixed size here. */
28421
28422                 DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, "
28423                                      "p_dst_base=%p, dst_length=%ld, valstack top=%ld",
28424                                      (void *) p_src_base, (long) src_length,
28425                                      (void *) p_dst_base, (long) dst_length,
28426                                      (long) duk_get_top(thr)));
28427
28428                 /* Ready to make the copy.  We must proceed element by element
28429                  * and must avoid any side effects that might cause the buffer
28430                  * validity check above to become invalid.
28431                  *
28432                  * Although we work through the value stack here, only plain
28433                  * numbers are handled which should be side effect safe.
28434                  */
28435
28436                 src_elem_size = (duk_small_uint_t) (1U << h_bufarg->shift);
28437                 dst_elem_size = (duk_small_uint_t) (1U << h_this->shift);
28438                 p_src = p_src_base;
28439                 p_dst = p_dst_base;
28440                 p_src_end = p_src_base + src_length;
28441
28442                 while (p_src != p_src_end) {
28443                         DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
28444                                              "p_src=%p, p_src_end=%p, p_dst=%p",
28445                                              (void *) p_src, (void *) p_src_end, (void *) p_dst));
28446                         /* A validated read() is always a number, so it's write coercion
28447                          * is always side effect free an won't invalidate pointers etc.
28448                          */
28449                         duk_hbufobj_push_validated_read(thr, h_bufarg, p_src, src_elem_size);
28450                         duk_hbufobj_validated_write(thr, h_this, p_dst, dst_elem_size);
28451                         duk_pop(thr);
28452                         p_src += src_elem_size;
28453                         p_dst += dst_elem_size;
28454                 }
28455
28456                 return 0;
28457         } else {
28458                 /* Slow path: quite slow, but we save space by using the property code
28459                  * to write coerce target values.  We don't need to worry about overlap
28460                  * here because the source is not a TypedArray.
28461                  *
28462                  * We could use the bufobj write coercion helper but since the
28463                  * property read may have arbitrary side effects, full validity checks
28464                  * would be needed for every element anyway.
28465                  */
28466
28467                 n = (duk_uarridx_t) duk_get_length(thr, 0);
28468                 DUK_ASSERT(offset_bytes <= h_this->length);
28469                 if ((n << h_this->shift) > h_this->length - offset_bytes) {
28470                         /* Overflow not an issue because subtraction is used on the right
28471                          * side and guaranteed to be >= 0.
28472                          */
28473                         DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
28474                         goto fail_args;
28475                 }
28476
28477                 /* There's no need to check for buffer validity status for the
28478                  * target here: the property access code will do that for each
28479                  * element.  Moreover, if we did check the validity here, side
28480                  * effects from reading the source argument might invalidate
28481                  * the results anyway.
28482                  */
28483
28484                 DUK_ASSERT_TOP(thr, 2);
28485                 duk_push_this(thr);
28486
28487                 for (i = 0; i < n; i++) {
28488                         duk_get_prop_index(thr, 0, i);
28489                         duk_put_prop_index(thr, 2, offset_elems + i);
28490                 }
28491         }
28492
28493         return 0;
28494
28495  fail_args:
28496         DUK_DCERROR_RANGE_INVALID_ARGS(thr);
28497 }
28498 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28499
28500 /*
28501  *  Node.js Buffer.prototype.slice([start], [end])
28502  *  ArrayBuffer.prototype.slice(begin, [end])
28503  *  TypedArray.prototype.subarray(begin, [end])
28504  *
28505  *  The API calls are almost identical; negative indices are counted from end
28506  *  of buffer, and final indices are clamped (allowing crossed indices).  Main
28507  *  differences:
28508  *
28509  *    - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create
28510  *      views, ArrayBuffer .slice() creates a copy
28511  *
28512  *    - Resulting object has a different class and prototype depending on the
28513  *      call (or 'this' argument)
28514  *
28515  *    - TypedArray .subarray() arguments are element indices, not byte offsets
28516  *
28517  *    - Plain buffer argument creates a plain buffer slice
28518  */
28519
28520 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28521 DUK_LOCAL void duk__arraybuffer_plain_slice(duk_hthread *thr, duk_hbuffer *h_val) {
28522         duk_int_t start_offset, end_offset;
28523         duk_uint_t slice_length;
28524         duk_uint8_t *p_copy;
28525         duk_size_t copy_length;
28526
28527         duk__clamp_startend_negidx_shifted(thr,
28528                                            (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val),
28529                                            0 /*buffer_shift*/,
28530                                            0 /*idx_start*/,
28531                                            1 /*idx_end*/,
28532                                            &start_offset,
28533                                            &end_offset);
28534         DUK_ASSERT(end_offset <= (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val));
28535         DUK_ASSERT(start_offset >= 0);
28536         DUK_ASSERT(end_offset >= start_offset);
28537         slice_length = (duk_uint_t) (end_offset - start_offset);
28538
28539         p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, (duk_size_t) slice_length);
28540         DUK_ASSERT(p_copy != NULL);
28541         copy_length = slice_length;
28542
28543         duk_memcpy_unsafe((void *) p_copy,
28544                           (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
28545                           copy_length);
28546 }
28547 #endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
28548
28549 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28550 /* Shared helper for slice/subarray operation.
28551  * Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling.
28552  */
28553 DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_hthread *thr) {
28554         duk_small_int_t magic;
28555         duk_small_uint_t res_class_num;
28556         duk_small_int_t res_proto_bidx;
28557         duk_hbufobj *h_this;
28558         duk_hbufobj *h_bufobj;
28559         duk_hbuffer *h_val;
28560         duk_int_t start_offset, end_offset;
28561         duk_uint_t slice_length;
28562         duk_tval *tv;
28563
28564         /* [ start end ] */
28565
28566         magic = duk_get_current_magic(thr);
28567
28568         tv = duk_get_borrowed_this_tval(thr);
28569         DUK_ASSERT(tv != NULL);
28570
28571         if (DUK_TVAL_IS_BUFFER(tv)) {
28572                 /* For plain buffers return a plain buffer slice. */
28573                 h_val = DUK_TVAL_GET_BUFFER(tv);
28574                 DUK_ASSERT(h_val != NULL);
28575
28576                 if (magic & 0x02) {
28577                         /* Make copy: ArrayBuffer.prototype.slice() uses this. */
28578                         duk__arraybuffer_plain_slice(thr, h_val);
28579                         return 1;
28580                 } else {
28581                         /* View into existing buffer: cannot be done if the
28582                          * result is a plain buffer because there's no slice
28583                          * info.  So return an ArrayBuffer instance; coerce
28584                          * the 'this' binding into an object and behave as if
28585                          * the original call was for an Object-coerced plain
28586                          * buffer (handled automatically by duk__require_bufobj_this()).
28587                          */
28588
28589                         DUK_DDD(DUK_DDDPRINT("slice() doesn't handle view into plain buffer, coerce 'this' to ArrayBuffer object"));
28590                         /* fall through */
28591                 }
28592         }
28593         tv = NULL;  /* No longer valid nor needed. */
28594
28595         h_this = duk__require_bufobj_this(thr);
28596
28597         /* Slice offsets are element (not byte) offsets, which only matters
28598          * for TypedArray views, Node.js Buffer and ArrayBuffer have shift
28599          * zero so byte and element offsets are the same.  Negative indices
28600          * are counted from end of slice, crossed indices are allowed (and
28601          * result in zero length result), and final values are clamped
28602          * against the current slice.  There's intentionally no check
28603          * against the underlying buffer here.
28604          */
28605
28606         duk__clamp_startend_negidx_shifted(thr,
28607                                            (duk_int_t) h_this->length,
28608                                            (duk_uint8_t) h_this->shift,
28609                                            0 /*idx_start*/,
28610                                            1 /*idx_end*/,
28611                                            &start_offset,
28612                                            &end_offset);
28613         DUK_ASSERT(end_offset >= start_offset);
28614         DUK_ASSERT(start_offset >= 0);
28615         DUK_ASSERT(end_offset >= 0);
28616         slice_length = (duk_uint_t) (end_offset - start_offset);
28617
28618         /* The resulting buffer object gets the same class and prototype as
28619          * the buffer in 'this', e.g. if the input is a Uint8Array the
28620          * result is a Uint8Array; if the input is a Float32Array, the
28621          * result is a Float32Array.  The result internal prototype should
28622          * be the default prototype for the class (e.g. initial value of
28623          * Uint8Array.prototype), not copied from the argument (Duktape 1.x
28624          * did that).
28625          *
28626          * Node.js Buffers have special handling: they're Uint8Arrays as far
28627          * as the internal class is concerned, so the new Buffer should also
28628          * be an Uint8Array but inherit from Buffer.prototype.
28629          */
28630         res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this);
28631         DUK_ASSERT(res_class_num >= DUK_HOBJECT_CLASS_BUFOBJ_MIN);  /* type check guarantees */
28632         DUK_ASSERT(res_class_num <= DUK_HOBJECT_CLASS_BUFOBJ_MAX);
28633         res_proto_bidx = duk__buffer_proto_from_classnum[res_class_num - DUK_HOBJECT_CLASS_BUFOBJ_MIN];
28634         if (magic & 0x04) {
28635                 res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE;
28636         }
28637         h_bufobj = duk_push_bufobj_raw(thr,
28638                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
28639                                        DUK_HOBJECT_FLAG_BUFOBJ |
28640                                        DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
28641                                        res_proto_bidx);
28642         DUK_ASSERT(h_bufobj != NULL);
28643
28644         DUK_ASSERT(h_bufobj->length == 0);
28645         h_bufobj->shift = h_this->shift;  /* inherit */
28646         h_bufobj->elem_type = h_this->elem_type;  /* inherit */
28647         h_bufobj->is_typedarray = magic & 0x01;
28648         DUK_ASSERT(h_bufobj->is_typedarray == 0 || h_bufobj->is_typedarray == 1);
28649
28650         h_val = h_this->buf;
28651         if (h_val == NULL) {
28652                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28653         }
28654
28655         if (magic & 0x02) {
28656                 /* non-zero: make copy */
28657                 duk_uint8_t *p_copy;
28658                 duk_size_t copy_length;
28659
28660                 p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, (duk_size_t) slice_length);  /* must be zeroed, not all bytes always copied */
28661                 DUK_ASSERT(p_copy != NULL);
28662
28663                 /* Copy slice, respecting underlying buffer limits; remainder
28664                  * is left as zero.
28665                  */
28666                 copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length);
28667                 duk_memcpy_unsafe((void *) p_copy,
28668                                   (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
28669                                   copy_length);
28670
28671                 h_val = duk_known_hbuffer(thr, -1);
28672
28673                 h_bufobj->buf = h_val;
28674                 DUK_HBUFFER_INCREF(thr, h_val);
28675                 h_bufobj->length = slice_length;
28676                 DUK_ASSERT(h_bufobj->offset == 0);
28677
28678                 duk_pop(thr);  /* reachable so pop OK */
28679         } else {
28680                 h_bufobj->buf = h_val;
28681                 DUK_HBUFFER_INCREF(thr, h_val);
28682                 h_bufobj->length = slice_length;
28683                 h_bufobj->offset = h_this->offset + (duk_uint_t) start_offset;
28684
28685                 /* Copy the .buffer property, needed for TypedArray.prototype.subarray().
28686                  *
28687                  * XXX: limit copy only for TypedArray classes specifically?
28688                  */
28689
28690                 DUK_ASSERT(h_bufobj->buf_prop == NULL);
28691                 h_bufobj->buf_prop = h_this->buf_prop;  /* may be NULL */
28692                 DUK_HOBJECT_INCREF_ALLOWNULL(thr, (duk_hobject *) h_bufobj->buf_prop);
28693         }
28694         /* unbalanced stack on purpose */
28695
28696         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
28697         return 1;
28698 }
28699 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28700
28701 /*
28702  *  Node.js Buffer.isEncoding()
28703  */
28704
28705 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28706 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_hthread *thr) {
28707         const char *encoding;
28708
28709         /* only accept lowercase 'utf8' now. */
28710
28711         encoding = duk_to_string(thr, 0);
28712         DUK_ASSERT(duk_is_string(thr, 0));  /* guaranteed by duk_to_string() */
28713         duk_push_boolean(thr, DUK_STRCMP(encoding, "utf8") == 0);
28714         return 1;
28715 }
28716 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28717
28718 /*
28719  *  Node.js Buffer.isBuffer()
28720  */
28721
28722 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28723 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_hthread *thr) {
28724         duk_hobject *h;
28725         duk_hobject *h_proto;
28726         duk_bool_t ret = 0;
28727
28728         DUK_ASSERT(duk_get_top(thr) >= 1);  /* nargs */
28729         h = duk_get_hobject(thr, 0);
28730         if (h != NULL) {
28731                 h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
28732                 DUK_ASSERT(h_proto != NULL);
28733
28734                 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
28735                 if (h != NULL) {
28736                         ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/);
28737                 }
28738         }
28739
28740         duk_push_boolean(thr, ret);
28741         return 1;
28742 }
28743 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28744
28745 /*
28746  *  Node.js Buffer.byteLength()
28747  */
28748
28749 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28750 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_hthread *thr) {
28751         const char *str;
28752         duk_size_t len;
28753
28754         /* At the moment Buffer(<str>) will just use the string bytes as
28755          * is (ignoring encoding), so we return the string length here
28756          * unconditionally.
28757          */
28758
28759         /* XXX: to be revised; Old Node.js behavior just coerces any buffer
28760          * values to string:
28761          * $ node
28762          * > Buffer.byteLength(new Uint32Array(10))
28763          * 20
28764          * > Buffer.byteLength(new Uint32Array(100))
28765          * 20
28766          * (The 20 comes from '[object Uint32Array]'.length
28767          */
28768
28769         str = duk_to_lstring(thr, 0, &len);
28770         DUK_UNREF(str);
28771         duk_push_size_t(thr, len);
28772         return 1;
28773 }
28774 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28775
28776 /*
28777  *  Node.js Buffer.concat()
28778  */
28779
28780 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28781 DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_hthread *thr) {
28782         duk_hobject *h_arg;
28783         duk_uint_t total_length;
28784         duk_hbufobj *h_bufobj;
28785         duk_hbufobj *h_bufres;
28786         duk_hbuffer *h_val;
28787         duk_uint_t i, n;
28788         duk_uint8_t *p;
28789         duk_size_t space_left;
28790         duk_size_t copy_size;
28791
28792         /* Node.js accepts only actual Arrays. */
28793         h_arg = duk_require_hobject(thr, 0);
28794         if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
28795                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28796         }
28797
28798         /* Compute result length and validate argument buffers. */
28799         n = (duk_uint_t) duk_get_length(thr, 0);
28800         total_length = 0;
28801         for (i = 0; i < n; i++) {
28802                 /* Neutered checks not necessary here: neutered buffers have
28803                  * zero 'length' so we'll effectively skip them.
28804                  */
28805                 DUK_ASSERT_TOP(thr, 2);  /* [ array totalLength ] */
28806                 duk_get_prop_index(thr, 0, (duk_uarridx_t) i);  /* -> [ array totalLength buf ] */
28807                 h_bufobj = duk__require_bufobj_value(thr, 2);
28808                 DUK_ASSERT(h_bufobj != NULL);
28809                 total_length += h_bufobj->length;
28810                 if (DUK_UNLIKELY(total_length < h_bufobj->length)) {
28811                         DUK_DCERROR_RANGE_INVALID_ARGS(thr);  /* Wrapped. */
28812                 }
28813                 duk_pop(thr);
28814         }
28815         /* In Node.js v0.12.1 a 1-element array is special and won't create a
28816          * copy, this was fixed later so an explicit check no longer needed.
28817          */
28818
28819         /* User totalLength overrides a computed length, but we'll check
28820          * every copy in the copy loop.  Note that duk_to_int() can
28821          * technically have arbitrary side effects so we need to recheck
28822          * the buffers in the copy loop.
28823          */
28824         if (!duk_is_undefined(thr, 1) && n > 0) {
28825                 /* For n == 0, Node.js ignores totalLength argument and
28826                  * returns a zero length buffer.
28827                  */
28828                 duk_int_t total_length_signed;
28829                 total_length_signed = duk_to_int(thr, 1);
28830                 if (total_length_signed < 0) {
28831                         DUK_DCERROR_RANGE_INVALID_ARGS(thr);
28832                 }
28833                 total_length = (duk_uint_t) total_length_signed;
28834         }
28835
28836         h_bufres = duk_push_bufobj_raw(thr,
28837                                        DUK_HOBJECT_FLAG_EXTENSIBLE |
28838                                        DUK_HOBJECT_FLAG_BUFOBJ |
28839                                        DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
28840                                        DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
28841         DUK_ASSERT(h_bufres != NULL);
28842
28843         p = (duk_uint8_t *) duk_push_fixed_buffer_zero(thr, total_length);  /* must be zeroed, all bytes not necessarily written over */
28844         DUK_ASSERT(p != NULL);
28845         space_left = (duk_size_t) total_length;
28846
28847         for (i = 0; i < n; i++) {
28848                 DUK_ASSERT_TOP(thr, 4);  /* [ array totalLength bufres buf ] */
28849
28850                 duk_get_prop_index(thr, 0, (duk_uarridx_t) i);
28851                 h_bufobj = duk__require_bufobj_value(thr, 4);
28852                 DUK_ASSERT(h_bufobj != NULL);
28853
28854                 copy_size = h_bufobj->length;
28855                 if (copy_size > space_left) {
28856                         copy_size = space_left;
28857                 }
28858
28859                 if (h_bufobj->buf != NULL &&
28860                     DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
28861                         duk_memcpy_unsafe((void *) p,
28862                                           (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
28863                                           copy_size);
28864                 } else {
28865                         /* Just skip, leaving zeroes in the result. */
28866                         ;
28867                 }
28868                 p += copy_size;
28869                 space_left -= copy_size;
28870
28871                 duk_pop(thr);
28872         }
28873
28874         h_val = duk_known_hbuffer(thr, -1);
28875
28876         duk__set_bufobj_buffer(thr, h_bufres, h_val);
28877         h_bufres->is_typedarray = 1;
28878         DUK_ASSERT_HBUFOBJ_VALID(h_bufres);
28879
28880         duk_pop(thr);  /* pop plain buffer, now reachable through h_bufres */
28881
28882         return 1;  /* return h_bufres */
28883 }
28884 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
28885
28886 /*
28887  *  Shared readfield and writefield methods
28888  *
28889  *  The readfield/writefield methods need support for endianness and field
28890  *  types.  All offsets are byte based so no offset shifting is needed.
28891  */
28892
28893 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
28894 /* Format of magic, bits:
28895  *   0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused
28896  *       3: endianness: 0=little, 1=big
28897  *       4: signed: 1=yes, 0=no
28898  *       5: typedarray: 1=yes, 0=no
28899  */
28900 #define  DUK__FLD_8BIT         0
28901 #define  DUK__FLD_16BIT        1
28902 #define  DUK__FLD_32BIT        2
28903 #define  DUK__FLD_FLOAT        3
28904 #define  DUK__FLD_DOUBLE       4
28905 #define  DUK__FLD_VARINT       5
28906 #define  DUK__FLD_BIGENDIAN    (1 << 3)
28907 #define  DUK__FLD_SIGNED       (1 << 4)
28908 #define  DUK__FLD_TYPEDARRAY   (1 << 5)
28909
28910 /* XXX: split into separate functions for each field type? */
28911 DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_hthread *thr) {
28912         duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr);
28913         duk_small_int_t magic_ftype;
28914         duk_small_int_t magic_bigendian;
28915         duk_small_int_t magic_signed;
28916         duk_small_int_t magic_typedarray;
28917         duk_small_int_t endswap;
28918         duk_hbufobj *h_this;
28919         duk_bool_t no_assert;
28920         duk_int_t offset_signed;
28921         duk_uint_t offset;
28922         duk_uint_t buffer_length;
28923         duk_uint_t check_length;
28924         duk_uint8_t *buf;
28925         duk_double_union du;
28926
28927         magic_ftype = magic & 0x0007;
28928         magic_bigendian = magic & 0x0008;
28929         magic_signed = magic & 0x0010;
28930         magic_typedarray = magic & 0x0020;
28931
28932         h_this = duk__require_bufobj_this(thr);  /* XXX: very inefficient for plain buffers */
28933         DUK_ASSERT(h_this != NULL);
28934         buffer_length = h_this->length;
28935
28936         /* [ offset noAssert                 ], when ftype != DUK__FLD_VARINT */
28937         /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
28938         /* [ offset littleEndian             ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
28939
28940         /* Handle TypedArray vs. Node.js Buffer arg differences */
28941         if (magic_typedarray) {
28942                 no_assert = 0;
28943 #if defined(DUK_USE_INTEGER_LE)
28944                 endswap = !duk_to_boolean(thr, 1);  /* 1=little endian */
28945 #else
28946                 endswap = duk_to_boolean(thr, 1);  /* 1=little endian */
28947 #endif
28948         } else {
28949                 no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
28950 #if defined(DUK_USE_INTEGER_LE)
28951                 endswap = magic_bigendian;
28952 #else
28953                 endswap = !magic_bigendian;
28954 #endif
28955         }
28956
28957         /* Offset is coerced first to signed integer range and then to unsigned.
28958          * This ensures we can add a small byte length (1-8) to the offset in
28959          * bound checks and not wrap.
28960          */
28961         offset_signed = duk_to_int(thr, 0);
28962         offset = (duk_uint_t) offset_signed;
28963         if (offset_signed < 0) {
28964                 goto fail_bounds;
28965         }
28966
28967         DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, "
28968                              "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
28969                              "endswap=%d",
28970                              (long) buffer_length, (long) offset, (int) no_assert,
28971                              (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
28972                              (int) (magic_signed >> 4), (int) endswap));
28973
28974         /* Update 'buffer_length' to be the effective, safe limit which
28975          * takes into account the underlying buffer.  This value will be
28976          * potentially invalidated by any side effect.
28977          */
28978         check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
28979         DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
28980                              (long) buffer_length, (long) check_length));
28981
28982         if (h_this->buf) {
28983                 buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
28984         } else {
28985                 /* Neutered.  We could go into the switch-case safely with
28986                  * buf == NULL because check_length == 0.  To avoid scanbuild
28987                  * warnings, fail directly instead.
28988                  */
28989                 DUK_ASSERT(check_length == 0);
28990                 goto fail_neutered;
28991         }
28992         DUK_ASSERT(buf != NULL);
28993
28994         switch (magic_ftype) {
28995         case DUK__FLD_8BIT: {
28996                 duk_uint8_t tmp;
28997                 if (offset + 1U > check_length) {
28998                         goto fail_bounds;
28999                 }
29000                 tmp = buf[offset];
29001                 if (magic_signed) {
29002                         duk_push_int(thr, (duk_int_t) ((duk_int8_t) tmp));
29003                 } else {
29004                         duk_push_uint(thr, (duk_uint_t) tmp);
29005                 }
29006                 break;
29007         }
29008         case DUK__FLD_16BIT: {
29009                 duk_uint16_t tmp;
29010                 if (offset + 2U > check_length) {
29011                         goto fail_bounds;
29012                 }
29013                 duk_memcpy((void *) du.uc, (const void *) (buf + offset), 2);
29014                 tmp = du.us[0];
29015                 if (endswap) {
29016                         tmp = DUK_BSWAP16(tmp);
29017                 }
29018                 if (magic_signed) {
29019                         duk_push_int(thr, (duk_int_t) ((duk_int16_t) tmp));
29020                 } else {
29021                         duk_push_uint(thr, (duk_uint_t) tmp);
29022                 }
29023                 break;
29024         }
29025         case DUK__FLD_32BIT: {
29026                 duk_uint32_t tmp;
29027                 if (offset + 4U > check_length) {
29028                         goto fail_bounds;
29029                 }
29030                 duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4);
29031                 tmp = du.ui[0];
29032                 if (endswap) {
29033                         tmp = DUK_BSWAP32(tmp);
29034                 }
29035                 if (magic_signed) {
29036                         duk_push_int(thr, (duk_int_t) ((duk_int32_t) tmp));
29037                 } else {
29038                         duk_push_uint(thr, (duk_uint_t) tmp);
29039                 }
29040                 break;
29041         }
29042         case DUK__FLD_FLOAT: {
29043                 duk_uint32_t tmp;
29044                 if (offset + 4U > check_length) {
29045                         goto fail_bounds;
29046                 }
29047                 duk_memcpy((void *) du.uc, (const void *) (buf + offset), 4);
29048                 if (endswap) {
29049                         tmp = du.ui[0];
29050                         tmp = DUK_BSWAP32(tmp);
29051                         du.ui[0] = tmp;
29052                 }
29053                 duk_push_number(thr, (duk_double_t) du.f[0]);
29054                 break;
29055         }
29056         case DUK__FLD_DOUBLE: {
29057                 if (offset + 8U > check_length) {
29058                         goto fail_bounds;
29059                 }
29060                 duk_memcpy((void *) du.uc, (const void *) (buf + offset), 8);
29061                 if (endswap) {
29062                         DUK_DBLUNION_BSWAP64(&du);
29063                 }
29064                 duk_push_number(thr, (duk_double_t) du.d);
29065                 break;
29066         }
29067         case DUK__FLD_VARINT: {
29068                 /* Node.js Buffer variable width integer field.  We don't really
29069                  * care about speed here, so aim for shortest algorithm.
29070                  */
29071                 duk_int_t field_bytelen;
29072                 duk_int_t i, i_step, i_end;
29073 #if defined(DUK_USE_64BIT_OPS)
29074                 duk_int64_t tmp;
29075                 duk_small_uint_t shift_tmp;
29076 #else
29077                 duk_double_t tmp;
29078                 duk_small_int_t highbyte;
29079 #endif
29080                 const duk_uint8_t *p;
29081
29082                 field_bytelen = duk_get_int(thr, 1);  /* avoid side effects! */
29083                 if (field_bytelen < 1 || field_bytelen > 6) {
29084                         goto fail_field_length;
29085                 }
29086                 if (offset + (duk_uint_t) field_bytelen > check_length) {
29087                         goto fail_bounds;
29088                 }
29089                 p = (const duk_uint8_t *) (buf + offset);
29090
29091                 /* Slow gathering of value using either 64-bit arithmetic
29092                  * or IEEE doubles if 64-bit types not available.  Handling
29093                  * of negative numbers is a bit non-obvious in both cases.
29094                  */
29095
29096                 if (magic_bigendian) {
29097                         /* Gather in big endian */
29098                         i = 0;
29099                         i_step = 1;
29100                         i_end = field_bytelen;  /* one i_step over */
29101                 } else {
29102                         /* Gather in little endian */
29103                         i = field_bytelen - 1;
29104                         i_step = -1;
29105                         i_end = -1;  /* one i_step over */
29106                 }
29107
29108 #if defined(DUK_USE_64BIT_OPS)
29109                 tmp = 0;
29110                 do {
29111                         DUK_ASSERT(i >= 0 && i < field_bytelen);
29112                         tmp = (tmp << 8) + (duk_int64_t) p[i];
29113                         i += i_step;
29114                 } while (i != i_end);
29115
29116                 if (magic_signed) {
29117                         /* Shift to sign extend.  Left shift must be unsigned
29118                          * to avoid undefined behavior; right shift must be
29119                          * signed to sign extend properly.
29120                          */
29121                         shift_tmp = (duk_small_uint_t) (64U - (duk_small_uint_t) field_bytelen * 8U);
29122                         tmp = (duk_int64_t) ((duk_uint64_t) tmp << shift_tmp) >> shift_tmp;
29123                 }
29124
29125                 duk_push_i64(thr, tmp);
29126 #else
29127                 highbyte = p[i];
29128                 if (magic_signed && (highbyte & 0x80) != 0) {
29129                         /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */
29130                         tmp = (duk_double_t) (highbyte - 256);
29131                 } else {
29132                         tmp = (duk_double_t) highbyte;
29133                 }
29134                 for (;;) {
29135                         i += i_step;
29136                         if (i == i_end) {
29137                                 break;
29138                         }
29139                         DUK_ASSERT(i >= 0 && i < field_bytelen);
29140                         tmp = (tmp * 256.0) + (duk_double_t) p[i];
29141                 }
29142
29143                 duk_push_number(thr, tmp);
29144 #endif
29145                 break;
29146         }
29147         default: {  /* should never happen but default here */
29148                 goto fail_bounds;
29149         }
29150         }
29151
29152         return 1;
29153
29154  fail_neutered:
29155  fail_field_length:
29156  fail_bounds:
29157         if (no_assert) {
29158                 /* Node.js return value for noAssert out-of-bounds reads is
29159                  * usually (but not always) NaN.  Return NaN consistently.
29160                  */
29161                 duk_push_nan(thr);
29162                 return 1;
29163         }
29164         DUK_DCERROR_RANGE_INVALID_ARGS(thr);
29165 }
29166 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
29167
29168 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29169 /* XXX: split into separate functions for each field type? */
29170 DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_hthread *thr) {
29171         duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(thr);
29172         duk_small_int_t magic_ftype;
29173         duk_small_int_t magic_bigendian;
29174         duk_small_int_t magic_signed;
29175         duk_small_int_t magic_typedarray;
29176         duk_small_int_t endswap;
29177         duk_hbufobj *h_this;
29178         duk_bool_t no_assert;
29179         duk_int_t offset_signed;
29180         duk_uint_t offset;
29181         duk_uint_t buffer_length;
29182         duk_uint_t check_length;
29183         duk_uint8_t *buf;
29184         duk_double_union du;
29185         duk_int_t nbytes = 0;
29186
29187         magic_ftype = magic & 0x0007;
29188         magic_bigendian = magic & 0x0008;
29189         magic_signed = magic & 0x0010;
29190         magic_typedarray = magic & 0x0020;
29191         DUK_UNREF(magic_signed);
29192
29193         h_this = duk__require_bufobj_this(thr);  /* XXX: very inefficient for plain buffers */
29194         DUK_ASSERT(h_this != NULL);
29195         buffer_length = h_this->length;
29196
29197         /* [ value  offset noAssert                 ], when ftype != DUK__FLD_VARINT */
29198         /* [ value  offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
29199         /* [ offset value  littleEndian             ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
29200
29201         /* Handle TypedArray vs. Node.js Buffer arg differences */
29202         if (magic_typedarray) {
29203                 no_assert = 0;
29204 #if defined(DUK_USE_INTEGER_LE)
29205                 endswap = !duk_to_boolean(thr, 2);  /* 1=little endian */
29206 #else
29207                 endswap = duk_to_boolean(thr, 2);  /* 1=little endian */
29208 #endif
29209                 duk_swap(thr, 0, 1);  /* offset/value order different from Node.js */
29210         } else {
29211                 no_assert = duk_to_boolean(thr, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
29212 #if defined(DUK_USE_INTEGER_LE)
29213                 endswap = magic_bigendian;
29214 #else
29215                 endswap = !magic_bigendian;
29216 #endif
29217         }
29218
29219         /* Offset is coerced first to signed integer range and then to unsigned.
29220          * This ensures we can add a small byte length (1-8) to the offset in
29221          * bound checks and not wrap.
29222          */
29223         offset_signed = duk_to_int(thr, 1);
29224         offset = (duk_uint_t) offset_signed;
29225
29226         /* We need 'nbytes' even for a failed offset; return value must be
29227          * (offset + nbytes) even when write fails due to invalid offset.
29228          */
29229         if (magic_ftype != DUK__FLD_VARINT) {
29230                 DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
29231                 nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
29232         } else {
29233                 nbytes = duk_get_int(thr, 2);
29234                 if (nbytes < 1 || nbytes > 6) {
29235                         goto fail_field_length;
29236                 }
29237         }
29238         DUK_ASSERT(nbytes >= 1 && nbytes <= 8);
29239
29240         /* Now we can check offset validity. */
29241         if (offset_signed < 0) {
29242                 goto fail_bounds;
29243         }
29244
29245         DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
29246                              "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
29247                              "endswap=%d",
29248                              duk_get_tval(thr, 0), (long) buffer_length, (long) offset, (int) no_assert,
29249                              (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
29250                              (int) (magic_signed >> 4), (int) endswap));
29251
29252         /* Coerce value to a number before computing check_length, so that
29253          * the field type specific coercion below can't have side effects
29254          * that would invalidate check_length.
29255          */
29256         duk_to_number(thr, 0);
29257
29258         /* Update 'buffer_length' to be the effective, safe limit which
29259          * takes into account the underlying buffer.  This value will be
29260          * potentially invalidated by any side effect.
29261          */
29262         check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
29263         DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
29264                              (long) buffer_length, (long) check_length));
29265
29266         if (h_this->buf) {
29267                 buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
29268         } else {
29269                 /* Neutered.  We could go into the switch-case safely with
29270                  * buf == NULL because check_length == 0.  To avoid scanbuild
29271                  * warnings, fail directly instead.
29272                  */
29273                 DUK_ASSERT(check_length == 0);
29274                 goto fail_neutered;
29275         }
29276         DUK_ASSERT(buf != NULL);
29277
29278         switch (magic_ftype) {
29279         case DUK__FLD_8BIT: {
29280                 if (offset + 1U > check_length) {
29281                         goto fail_bounds;
29282                 }
29283                 /* sign doesn't matter when writing */
29284                 buf[offset] = (duk_uint8_t) duk_to_uint32(thr, 0);
29285                 break;
29286         }
29287         case DUK__FLD_16BIT: {
29288                 duk_uint16_t tmp;
29289                 if (offset + 2U > check_length) {
29290                         goto fail_bounds;
29291                 }
29292                 tmp = (duk_uint16_t) duk_to_uint32(thr, 0);
29293                 if (endswap) {
29294                         tmp = DUK_BSWAP16(tmp);
29295                 }
29296                 du.us[0] = tmp;
29297                 /* sign doesn't matter when writing */
29298                 duk_memcpy((void *) (buf + offset), (const void *) du.uc, 2);
29299                 break;
29300         }
29301         case DUK__FLD_32BIT: {
29302                 duk_uint32_t tmp;
29303                 if (offset + 4U > check_length) {
29304                         goto fail_bounds;
29305                 }
29306                 tmp = (duk_uint32_t) duk_to_uint32(thr, 0);
29307                 if (endswap) {
29308                         tmp = DUK_BSWAP32(tmp);
29309                 }
29310                 du.ui[0] = tmp;
29311                 /* sign doesn't matter when writing */
29312                 duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4);
29313                 break;
29314         }
29315         case DUK__FLD_FLOAT: {
29316                 duk_uint32_t tmp;
29317                 if (offset + 4U > check_length) {
29318                         goto fail_bounds;
29319                 }
29320                 du.f[0] = (duk_float_t) duk_to_number(thr, 0);
29321                 if (endswap) {
29322                         tmp = du.ui[0];
29323                         tmp = DUK_BSWAP32(tmp);
29324                         du.ui[0] = tmp;
29325                 }
29326                 /* sign doesn't matter when writing */
29327                 duk_memcpy((void *) (buf + offset), (const void *) du.uc, 4);
29328                 break;
29329         }
29330         case DUK__FLD_DOUBLE: {
29331                 if (offset + 8U > check_length) {
29332                         goto fail_bounds;
29333                 }
29334                 du.d = (duk_double_t) duk_to_number(thr, 0);
29335                 if (endswap) {
29336                         DUK_DBLUNION_BSWAP64(&du);
29337                 }
29338                 /* sign doesn't matter when writing */
29339                 duk_memcpy((void *) (buf + offset), (const void *) du.uc, 8);
29340                 break;
29341         }
29342         case DUK__FLD_VARINT: {
29343                 /* Node.js Buffer variable width integer field.  We don't really
29344                  * care about speed here, so aim for shortest algorithm.
29345                  */
29346                 duk_int_t field_bytelen;
29347                 duk_int_t i, i_step, i_end;
29348 #if defined(DUK_USE_64BIT_OPS)
29349                 duk_int64_t tmp;
29350 #else
29351                 duk_double_t tmp;
29352 #endif
29353                 duk_uint8_t *p;
29354
29355                 field_bytelen = (duk_int_t) nbytes;
29356                 if (offset + (duk_uint_t) field_bytelen > check_length) {
29357                         goto fail_bounds;
29358                 }
29359
29360                 /* Slow writing of value using either 64-bit arithmetic
29361                  * or IEEE doubles if 64-bit types not available.  There's
29362                  * no special sign handling when writing varints.
29363                  */
29364
29365                 if (magic_bigendian) {
29366                         /* Write in big endian */
29367                         i = field_bytelen;  /* one i_step added at top of loop */
29368                         i_step = -1;
29369                         i_end = 0;
29370                 } else {
29371                         /* Write in little endian */
29372                         i = -1;  /* one i_step added at top of loop */
29373                         i_step = 1;
29374                         i_end = field_bytelen - 1;
29375                 }
29376
29377                 /* XXX: The duk_to_number() cast followed by integer coercion
29378                  * is platform specific so NaN, +/- Infinity, and out-of-bounds
29379                  * values result in platform specific output now.
29380                  * See: test-bi-nodejs-buffer-proto-varint-special.js
29381                  */
29382
29383 #if defined(DUK_USE_64BIT_OPS)
29384                 tmp = (duk_int64_t) duk_to_number(thr, 0);
29385                 p = (duk_uint8_t *) (buf + offset);
29386                 do {
29387                         i += i_step;
29388                         DUK_ASSERT(i >= 0 && i < field_bytelen);
29389                         p[i] = (duk_uint8_t) (tmp & 0xff);
29390                         tmp = tmp >> 8;  /* unnecessary shift for last byte */
29391                 } while (i != i_end);
29392 #else
29393                 tmp = duk_to_number(thr, 0);
29394                 p = (duk_uint8_t *) (buf + offset);
29395                 do {
29396                         i += i_step;
29397                         tmp = DUK_FLOOR(tmp);
29398                         DUK_ASSERT(i >= 0 && i < field_bytelen);
29399                         p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0));
29400                         tmp = tmp / 256.0;  /* unnecessary div for last byte */
29401                 } while (i != i_end);
29402 #endif
29403                 break;
29404         }
29405         default: {  /* should never happen but default here */
29406                 goto fail_bounds;
29407         }
29408         }
29409
29410         /* Node.js Buffer: return offset + #bytes written (i.e. next
29411          * write offset).
29412          */
29413         if (magic_typedarray) {
29414                 /* For TypedArrays 'undefined' return value is specified
29415                  * by ES2015 (matches V8).
29416                  */
29417                 return 0;
29418         }
29419         duk_push_uint(thr, offset + (duk_uint_t) nbytes);
29420         return 1;
29421
29422  fail_neutered:
29423  fail_field_length:
29424  fail_bounds:
29425         if (no_assert) {
29426                 /* Node.js return value for failed writes is offset + #bytes
29427                  * that would have been written.
29428                  */
29429                 /* XXX: for negative input offsets, 'offset' will be a large
29430                  * positive value so the result here is confusing.
29431                  */
29432                 if (magic_typedarray) {
29433                         return 0;
29434                 }
29435                 duk_push_uint(thr, offset + (duk_uint_t) nbytes);
29436                 return 1;
29437         }
29438         DUK_DCERROR_RANGE_INVALID_ARGS(thr);
29439 }
29440 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
29441
29442 /*
29443  *  Accessors for .buffer, .byteLength, .byteOffset
29444  */
29445
29446 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29447 DUK_LOCAL duk_hbufobj *duk__autospawn_arraybuffer(duk_hthread *thr, duk_hbuffer *h_buf) {
29448         duk_hbufobj *h_res;
29449
29450         h_res = duk_push_bufobj_raw(thr,
29451                                     DUK_HOBJECT_FLAG_EXTENSIBLE |
29452                                     DUK_HOBJECT_FLAG_BUFOBJ |
29453                                     DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
29454                                     DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
29455         DUK_ASSERT(h_res != NULL);
29456         DUK_UNREF(h_res);
29457
29458         duk__set_bufobj_buffer(thr, h_res, h_buf);
29459         DUK_ASSERT_HBUFOBJ_VALID(h_res);
29460         DUK_ASSERT(h_res->buf_prop == NULL);
29461         return h_res;
29462 }
29463
29464 DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
29465         duk_hbufobj *h_bufobj;
29466
29467         h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
29468         DUK_ASSERT(h_bufobj != NULL);
29469         if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
29470                 DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for plain buffer"));
29471                 (void) duk__autospawn_arraybuffer(thr, (duk_hbuffer *) h_bufobj);
29472                 return 1;
29473         } else {
29474                 if (h_bufobj->buf_prop == NULL &&
29475                     DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufobj) != DUK_HOBJECT_CLASS_ARRAYBUFFER &&
29476                     h_bufobj->buf != NULL) {
29477                         duk_hbufobj *h_arrbuf;
29478
29479                         DUK_DD(DUK_DDPRINT("autospawn ArrayBuffer for typed array or DataView"));
29480                         h_arrbuf = duk__autospawn_arraybuffer(thr, h_bufobj->buf);
29481
29482                         if (h_bufobj->buf_prop == NULL) {
29483                                 /* Must recheck buf_prop, in case ArrayBuffer
29484                                  * alloc had a side effect which already filled
29485                                  * it!
29486                                  */
29487
29488                                 /* Set ArrayBuffer's .byteOffset and .byteLength based
29489                                  * on the view so that Arraybuffer[view.byteOffset]
29490                                  * matches view[0].
29491                                  */
29492                                 h_arrbuf->offset = 0;
29493                                 DUK_ASSERT(h_bufobj->offset + h_bufobj->length >= h_bufobj->offset);  /* Wrap check on creation. */
29494                                 h_arrbuf->length = h_bufobj->offset + h_bufobj->length;
29495                                 DUK_ASSERT(h_arrbuf->buf_prop == NULL);
29496
29497                                 DUK_ASSERT(h_bufobj->buf_prop == NULL);
29498                                 h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
29499                                 DUK_HBUFOBJ_INCREF(thr, h_arrbuf);  /* Now reachable and accounted for. */
29500                         }
29501
29502                         /* Left on stack; pushed for the second time below (OK). */
29503                 }
29504                 if (h_bufobj->buf_prop) {
29505                         duk_push_hobject(thr, h_bufobj->buf_prop);
29506                         return 1;
29507                 }
29508         }
29509         return 0;
29510 }
29511
29512 DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
29513         duk_hbufobj *h_bufobj;
29514
29515         h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
29516         DUK_ASSERT(h_bufobj != NULL);
29517         if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
29518                 duk_push_uint(thr, 0);
29519         } else {
29520                 /* If neutered must return 0; offset is zeroed during
29521                  * neutering.
29522                  */
29523                 duk_push_uint(thr, h_bufobj->offset);
29524         }
29525         return 1;
29526 }
29527
29528 DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
29529         duk_hbufobj *h_bufobj;
29530
29531         h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(thr, DUK__BUFOBJ_FLAG_THROW /*flags*/);
29532         DUK_ASSERT(h_bufobj != NULL);
29533         if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
29534                 duk_hbuffer *h_buf;
29535
29536                 h_buf = (duk_hbuffer *) h_bufobj;
29537                 DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX);  /* Buffer limits. */
29538                 duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
29539         } else {
29540                 /* If neutered must return 0; length is zeroed during
29541                  * neutering.
29542                  */
29543                 duk_push_uint(thr, h_bufobj->length);
29544         }
29545         return 1;
29546 }
29547 #else  /* DUK_USE_BUFFEROBJECT_SUPPORT */
29548 /* No .buffer getter without ArrayBuffer support. */
29549 #if 0
29550 DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_hthread *thr) {
29551         return 0;
29552 }
29553 #endif
29554
29555 DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_hthread *thr) {
29556         duk_push_uint(thr, 0);
29557         return 1;
29558 }
29559
29560 DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_hthread *thr) {
29561         duk_hbuffer *h_buf;
29562
29563         /* XXX: helper? */
29564         duk_push_this(thr);
29565         h_buf = duk_require_hbuffer(thr, -1);
29566         duk_push_uint(thr, DUK_HBUFFER_GET_SIZE(h_buf));
29567         return 1;
29568 }
29569 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
29570
29571 /* automatic undefs */
29572 #undef DUK__BUFOBJ_FLAG_PROMOTE
29573 #undef DUK__BUFOBJ_FLAG_THROW
29574 #undef DUK__FLD_16BIT
29575 #undef DUK__FLD_32BIT
29576 #undef DUK__FLD_8BIT
29577 #undef DUK__FLD_BIGENDIAN
29578 #undef DUK__FLD_DOUBLE
29579 #undef DUK__FLD_FLOAT
29580 #undef DUK__FLD_SIGNED
29581 #undef DUK__FLD_TYPEDARRAY
29582 #undef DUK__FLD_VARINT
29583 #line 1 "duk_bi_date.c"
29584 /*
29585  *  Date built-ins
29586  *
29587  *  Unlike most built-ins, Date has some platform dependencies for getting
29588  *  UTC time, converting between UTC and local time, and parsing and
29589  *  formatting time values.  These are all abstracted behind DUK_USE_xxx
29590  *  config options.  There are built-in platform specific providers for
29591  *  POSIX and Windows, but external providers can also be used.
29592  *
29593  *  See doc/datetime.rst.
29594  *
29595  */
29596
29597 /* #include duk_internal.h -> already included */
29598
29599 /* XXX: currently defines unnecessary symbols when DUK_USE_DATE_BUILTIN is disabled. */
29600
29601 /*
29602  *  Forward declarations
29603  */
29604
29605 DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset);
29606 DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags);
29607 DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val);
29608 DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags);
29609
29610 /*
29611  *  Other file level defines
29612  */
29613
29614 /* Debug macro to print all parts and dparts (used manually because of debug level). */
29615 #define  DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts)  do { \
29616                 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
29617                                  (long) (parts)[0], (long) (parts)[1], \
29618                                  (long) (parts)[2], (long) (parts)[3], \
29619                                  (long) (parts)[4], (long) (parts)[5], \
29620                                  (long) (parts)[6], (long) (parts)[7], \
29621                                  (double) (dparts)[0], (double) (dparts)[1], \
29622                                  (double) (dparts)[2], (double) (dparts)[3], \
29623                                  (double) (dparts)[4], (double) (dparts)[5], \
29624                                  (double) (dparts)[6], (double) (dparts)[7])); \
29625         } while (0)
29626 #define  DUK__DPRINT_PARTS(parts)  do { \
29627                 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \
29628                                  (long) (parts)[0], (long) (parts)[1], \
29629                                  (long) (parts)[2], (long) (parts)[3], \
29630                                  (long) (parts)[4], (long) (parts)[5], \
29631                                  (long) (parts)[6], (long) (parts)[7])); \
29632         } while (0)
29633 #define  DUK__DPRINT_DPARTS(dparts)  do { \
29634                 DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
29635                                  (double) (dparts)[0], (double) (dparts)[1], \
29636                                  (double) (dparts)[2], (double) (dparts)[3], \
29637                                  (double) (dparts)[4], (double) (dparts)[5], \
29638                                  (double) (dparts)[6], (double) (dparts)[7])); \
29639         } while (0)
29640
29641 /* Equivalent year for DST calculations outside [1970,2038[ range, see
29642  * E5 Section 15.9.1.8.  Equivalent year has the same leap-year-ness and
29643  * starts with the same weekday on Jan 1.
29644  * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
29645  */
29646 #define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
29647 DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
29648 #if 1
29649         /* This is based on V8 EquivalentYear() algorithm (see util/genequivyear.py):
29650          * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
29651          */
29652
29653         /* non-leap year: sunday, monday, ... */
29654         DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031),
29655         DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011),
29656
29657         /* leap year: sunday, monday, ... */
29658         DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020),
29659         DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028)
29660 #endif
29661
29662 #if 0
29663         /* This is based on Rhino EquivalentYear() algorithm:
29664          * https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java
29665          */
29666
29667         /* non-leap year: sunday, monday, ... */
29668         DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986),
29669         DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977),
29670
29671         /* leap year: sunday, monday, ... */
29672         DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992),
29673         DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
29674 #endif
29675 };
29676
29677 /*
29678  *  ISO 8601 subset parser.
29679  */
29680
29681 /* Parser part count. */
29682 #define DUK__NUM_ISO8601_PARSER_PARTS  9
29683
29684 /* Parser part indices. */
29685 #define DUK__PI_YEAR         0
29686 #define DUK__PI_MONTH        1
29687 #define DUK__PI_DAY          2
29688 #define DUK__PI_HOUR         3
29689 #define DUK__PI_MINUTE       4
29690 #define DUK__PI_SECOND       5
29691 #define DUK__PI_MILLISECOND  6
29692 #define DUK__PI_TZHOUR       7
29693 #define DUK__PI_TZMINUTE     8
29694
29695 /* Parser part masks. */
29696 #define DUK__PM_YEAR         (1 << DUK__PI_YEAR)
29697 #define DUK__PM_MONTH        (1 << DUK__PI_MONTH)
29698 #define DUK__PM_DAY          (1 << DUK__PI_DAY)
29699 #define DUK__PM_HOUR         (1 << DUK__PI_HOUR)
29700 #define DUK__PM_MINUTE       (1 << DUK__PI_MINUTE)
29701 #define DUK__PM_SECOND       (1 << DUK__PI_SECOND)
29702 #define DUK__PM_MILLISECOND  (1 << DUK__PI_MILLISECOND)
29703 #define DUK__PM_TZHOUR       (1 << DUK__PI_TZHOUR)
29704 #define DUK__PM_TZMINUTE     (1 << DUK__PI_TZMINUTE)
29705
29706 /* Parser separator indices. */
29707 #define DUK__SI_PLUS         0
29708 #define DUK__SI_MINUS        1
29709 #define DUK__SI_T            2
29710 #define DUK__SI_SPACE        3
29711 #define DUK__SI_COLON        4
29712 #define DUK__SI_PERIOD       5
29713 #define DUK__SI_Z            6
29714 #define DUK__SI_NUL          7
29715
29716 /* Parser separator masks. */
29717 #define DUK__SM_PLUS         (1 << DUK__SI_PLUS)
29718 #define DUK__SM_MINUS        (1 << DUK__SI_MINUS)
29719 #define DUK__SM_T            (1 << DUK__SI_T)
29720 #define DUK__SM_SPACE        (1 << DUK__SI_SPACE)
29721 #define DUK__SM_COLON        (1 << DUK__SI_COLON)
29722 #define DUK__SM_PERIOD       (1 << DUK__SI_PERIOD)
29723 #define DUK__SM_Z            (1 << DUK__SI_Z)
29724 #define DUK__SM_NUL          (1 << DUK__SI_NUL)
29725
29726 /* Rule control flags. */
29727 #define DUK__CF_NEG          (1 << 0)  /* continue matching, set neg_tzoffset flag */
29728 #define DUK__CF_ACCEPT       (1 << 1)  /* accept string */
29729 #define DUK__CF_ACCEPT_NUL   (1 << 2)  /* accept string if next char is NUL (otherwise reject) */
29730
29731 #define DUK__PACK_RULE(partmask,sepmask,nextpart,flags)  \
29732         ((duk_uint32_t) (partmask) + \
29733          (((duk_uint32_t) (sepmask)) << 9) + \
29734          (((duk_uint32_t) (nextpart)) << 17) + \
29735          (((duk_uint32_t) (flags)) << 21))
29736
29737 #define DUK__UNPACK_RULE(rule,var_nextidx,var_flags)  do { \
29738                 (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \
29739                 (var_flags) = (duk_small_uint_t) ((rule) >> 21); \
29740         } while (0)
29741
29742 #define DUK__RULE_MASK_PART_SEP  0x1ffffUL
29743
29744 /* Matching separator index is used in the control table */
29745 DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = {
29746         DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, DUK_ASC_SPACE /*3*/,
29747         DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, DUK_ASC_NUL /*7*/
29748 };
29749
29750 /* Rule table: first matching rule is used to determine what to do next. */
29751 DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
29752         DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0),
29753         DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0),
29754         DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0),
29755         DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0),
29756         DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0),
29757         DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0),
29758         DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0),
29759         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),
29760         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),
29761         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),
29762         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)
29763
29764         /* Note1: the specification doesn't require matching a time form with
29765          *        just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z".
29766          *
29767          * Note2: the specification doesn't require matching a timezone offset
29768          *        with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02"
29769          */
29770 };
29771
29772 DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_hthread *thr, const char *str) {
29773         duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
29774         duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
29775         duk_double_t d;
29776         const duk_uint8_t *p;
29777         duk_small_uint_t part_idx = 0;
29778         duk_int_t accum = 0;
29779         duk_small_uint_t ndigits = 0;
29780         duk_bool_t neg_year = 0;
29781         duk_bool_t neg_tzoffset = 0;
29782         duk_uint_fast8_t ch;
29783         duk_small_uint_t i;
29784
29785         /* During parsing, month and day are one-based; set defaults here. */
29786         duk_memzero(parts, sizeof(parts));
29787         DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0);  /* don't care value, year is mandatory */
29788         parts[DUK_DATE_IDX_MONTH] = 1;
29789         parts[DUK_DATE_IDX_DAY] = 1;
29790
29791         /* Special handling for year sign. */
29792         p = (const duk_uint8_t *) str;
29793         ch = p[0];
29794         if (ch == DUK_ASC_PLUS) {
29795                 p++;
29796         } else if (ch == DUK_ASC_MINUS) {
29797                 neg_year = 1;
29798                 p++;
29799         }
29800
29801         for (;;) {
29802                 ch = *p++;
29803                 DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')",
29804                                      (long) part_idx, (long) ch,
29805                                      (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : DUK_ASC_QUESTION)));
29806
29807                 if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) {
29808                         if (ndigits >= 9) {
29809                                 DUK_DDD(DUK_DDDPRINT("too many digits -> reject"));
29810                                 goto reject;
29811                         }
29812                         if (part_idx == DUK__PI_MILLISECOND && ndigits >= 3) {
29813                                 /* ignore millisecond fractions after 3 */
29814                         } else {
29815                                 accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00;
29816                                 ndigits++;
29817                         }
29818                 } else {
29819                         duk_uint_fast32_t match_val;
29820                         duk_small_uint_t sep_idx;
29821
29822                         if (ndigits <= 0) {
29823                                 goto reject;
29824                         }
29825                         if (part_idx == DUK__PI_MILLISECOND) {
29826                                 /* complete the millisecond field */
29827                                 while (ndigits < 3) {
29828                                         accum *= 10;
29829                                         ndigits++;
29830                                 }
29831                         }
29832                         parts[part_idx] = accum;
29833                         DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld", (long) part_idx, (long) accum));
29834
29835                         accum = 0;
29836                         ndigits = 0;
29837
29838                         for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) {
29839                                 if (duk__parse_iso8601_seps[i] == ch) {
29840                                         break;
29841                                 }
29842                         }
29843                         if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) {
29844                                 DUK_DDD(DUK_DDDPRINT("separator character doesn't match -> reject"));
29845                                 goto reject;
29846                         }
29847
29848                         sep_idx = i;
29849                         match_val = (1UL << part_idx) + (1UL << (sep_idx + 9));  /* match against rule part/sep bits */
29850
29851                         for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) {
29852                                 duk_uint_fast32_t rule = duk__parse_iso8601_control[i];
29853                                 duk_small_uint_t nextpart;
29854                                 duk_small_uint_t cflags;
29855
29856                                 DUK_DDD(DUK_DDDPRINT("part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx",
29857                                                      (long) part_idx, (long) sep_idx,
29858                                                      (unsigned long) match_val, (unsigned long) rule));
29859
29860                                 if ((rule & match_val) != match_val) {
29861                                         continue;
29862                                 }
29863
29864                                 DUK__UNPACK_RULE(rule, nextpart, cflags);
29865
29866                                 DUK_DDD(DUK_DDDPRINT("rule match -> part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, "
29867                                                      "rule=0x%08lx -> nextpart=%ld, cflags=0x%02lx",
29868                                                      (long) part_idx, (long) sep_idx,
29869                                                      (unsigned long) match_val, (unsigned long) rule,
29870                                                      (long) nextpart, (unsigned long) cflags));
29871
29872                                 if (cflags & DUK__CF_NEG) {
29873                                         neg_tzoffset = 1;
29874                                 }
29875
29876                                 if (cflags & DUK__CF_ACCEPT) {
29877                                         goto accept;
29878                                 }
29879
29880                                 if (cflags & DUK__CF_ACCEPT_NUL) {
29881                                         DUK_ASSERT(*(p - 1) != (char) 0);
29882                                         if (*p == DUK_ASC_NUL) {
29883                                                 goto accept;
29884                                         }
29885                                         goto reject;
29886                                 }
29887
29888                                 part_idx = nextpart;
29889                                 break;
29890                         }  /* rule match */
29891
29892                         if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) {
29893                                 DUK_DDD(DUK_DDDPRINT("no rule matches -> reject"));
29894                                 goto reject;
29895                         }
29896
29897                         if (ch == 0) {
29898                                 /* This shouldn't be necessary, but check just in case
29899                                  * to avoid any chance of overruns.
29900                                  */
29901                                 DUK_DDD(DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject"));
29902                                 goto reject;
29903                         }
29904                 }  /* if-digit-else-ctrl */
29905         }  /* char loop */
29906
29907         /* We should never exit the loop above. */
29908         DUK_UNREACHABLE();
29909
29910  reject:
29911         DUK_DDD(DUK_DDDPRINT("reject"));
29912         return 0;
29913
29914  accept:
29915         DUK_DDD(DUK_DDDPRINT("accept"));
29916
29917         /* Apply timezone offset to get the main parts in UTC */
29918         if (neg_year) {
29919                 parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR];
29920         }
29921         if (neg_tzoffset) {
29922                 parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR];
29923                 parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE];
29924         } else {
29925                 parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR];
29926                 parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE];
29927         }
29928         parts[DUK__PI_MONTH] -= 1;  /* zero-based month */
29929         parts[DUK__PI_DAY] -= 1;  /* zero-based day */
29930
29931         /* Use double parts, they tolerate unnormalized time.
29932          *
29933          * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR)
29934          * on purpose.  It won't be actually used by duk_bi_date_get_timeval_from_dparts(),
29935          * but will make the value initialized just in case, and avoid any
29936          * potential for Valgrind issues.
29937          */
29938         for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
29939                 DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld", (long) i, (long) parts[i]));
29940                 dparts[i] = parts[i];
29941         }
29942
29943         d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
29944         duk_push_number(thr, d);
29945         return 1;
29946 }
29947
29948 /*
29949  *  Date/time parsing helper.
29950  *
29951  *  Parse a datetime string into a time value.  We must first try to parse
29952  *  the input according to the standard format in E5.1 Section 15.9.1.15.
29953  *  If that fails, we can try to parse using custom parsing, which can
29954  *  either be platform neutral (custom code) or platform specific (using
29955  *  existing platform API calls).
29956  *
29957  *  Note in particular that we must parse whatever toString(), toUTCString(),
29958  *  and toISOString() can produce; see E5.1 Section 15.9.4.2.
29959  *
29960  *  Returns 1 to allow tail calling.
29961  *
29962  *  There is much room for improvement here with respect to supporting
29963  *  alternative datetime formats.  For instance, V8 parses '2012-01-01' as
29964  *  UTC and '2012/01/01' as local time.
29965  */
29966
29967 DUK_LOCAL duk_ret_t duk__parse_string(duk_hthread *thr, const char *str) {
29968         /* XXX: there is a small risk here: because the ISO 8601 parser is
29969          * very loose, it may end up parsing some datetime values which
29970          * would be better parsed with a platform specific parser.
29971          */
29972
29973         DUK_ASSERT(str != NULL);
29974         DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
29975
29976         if (duk__parse_string_iso8601_subset(thr, str) != 0) {
29977                 return 1;
29978         }
29979
29980 #if defined(DUK_USE_DATE_PARSE_STRING)
29981         /* Contract, either:
29982          * - Push value on stack and return 1
29983          * - Don't push anything on stack and return 0
29984          */
29985
29986         if (DUK_USE_DATE_PARSE_STRING(thr, str) != 0) {
29987                 return 1;
29988         }
29989 #else
29990         /* No platform-specific parsing, this is not an error. */
29991 #endif
29992
29993         duk_push_nan(thr);
29994         return 1;
29995 }
29996
29997 /*
29998  *  Calendar helpers
29999  *
30000  *  Some helpers are used for getters and can operate on normalized values
30001  *  which can be represented with 32-bit signed integers.  Other helpers are
30002  *  needed by setters and operate on un-normalized double values, must watch
30003  *  out for non-finite numbers etc.
30004  */
30005
30006 DUK_LOCAL duk_uint8_t duk__days_in_month[12] = {
30007         (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30,
30008         (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31,
30009         (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31
30010 };
30011
30012 /* Maximum iteration count for computing UTC-to-local time offset when
30013  * creating an ECMAScript time value from local parts.
30014  */
30015 #define DUK__LOCAL_TZOFFSET_MAXITER   4
30016
30017 /* Because 'day since epoch' can be negative and is used to compute weekday
30018  * using a modulo operation, add this multiple of 7 to avoid negative values
30019  * when year is below 1970 epoch.  ECMAScript time values are restricted to
30020  * +/- 100 million days from epoch, so this adder fits nicely into 32 bits.
30021  * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin.
30022  */
30023 #define DUK__WEEKDAY_MOD_ADDER  (20000000 * 7)  /* 0x08583b00 */
30024
30025 DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) {
30026         if ((year % 4) != 0) {
30027                 return 0;
30028         }
30029         if ((year % 100) != 0) {
30030                 return 1;
30031         }
30032         if ((year % 400) != 0) {
30033                 return 0;
30034         }
30035         return 1;
30036 }
30037
30038 DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) {
30039         return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS);
30040 }
30041
30042 DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) {
30043         return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= DUK_DATE_MSEC_100M_DAYS_LEEWAY);
30044 }
30045
30046 DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) {
30047         return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR);
30048 }
30049
30050 DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) {
30051         if (!DUK_ISFINITE(x)) {
30052                 return DUK_DOUBLE_NAN;
30053         }
30054
30055         if (!duk_bi_date_timeval_in_valid_range(x)) {
30056                 return DUK_DOUBLE_NAN;
30057         }
30058
30059         x = duk_js_tointeger_number(x);
30060
30061         /* Here we'd have the option to normalize -0 to +0. */
30062         return x;
30063 }
30064
30065 /* Integer division which floors also negative values correctly. */
30066 DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) {
30067         DUK_ASSERT(b > 0);
30068         if (a >= 0) {
30069                 return a / b;
30070         } else {
30071                 /* e.g. a = -4, b = 5  -->  -4 - 5 + 1 / 5  -->  -8 / 5  -->  -1
30072                  *      a = -5, b = 5  -->  -5 - 5 + 1 / 5  -->  -9 / 5  -->  -1
30073                  *      a = -6, b = 5  -->  -6 - 5 + 1 / 5  -->  -10 / 5  -->  -2
30074                  */
30075                 return (a - b + 1) / b;
30076         }
30077 }
30078
30079 /* Compute day number of the first day of a given year. */
30080 DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) {
30081         /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative
30082          * values, but is incorrect for negative ones.
30083          */
30084         return 365 * (year - 1970)
30085                + duk__div_floor(year - 1969, 4)
30086                - duk__div_floor(year - 1901, 100)
30087                + duk__div_floor(year - 1601, 400);
30088 }
30089
30090 /* Given a day number, determine year and day-within-year. */
30091 DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year) {
30092         duk_int_t year;
30093         duk_int_t diff_days;
30094
30095         /* estimate year upwards (towards positive infinity), then back down;
30096          * two iterations should be enough
30097          */
30098
30099         if (day >= 0) {
30100                 year = 1970 + day / 365;
30101         } else {
30102                 year = 1970 + day / 366;
30103         }
30104
30105         for (;;) {
30106                 diff_days = duk__day_from_year(year) - day;
30107                 DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld", (long) year, (long) day, (long) diff_days));
30108                 if (diff_days <= 0) {
30109                         DUK_ASSERT(-diff_days < 366);  /* fits into duk_small_int_t */
30110                         *out_day_within_year = -diff_days;
30111                         DUK_DDD(DUK_DDDPRINT("--> year=%ld, day-within-year=%ld",
30112                                              (long) year, (long) *out_day_within_year));
30113                         DUK_ASSERT(*out_day_within_year >= 0);
30114                         DUK_ASSERT(*out_day_within_year < (duk_bi_date_is_leap_year(year) ? 366 : 365));
30115                         return year;
30116                 }
30117
30118                 /* Note: this is very tricky; we must never 'overshoot' the
30119                  * correction downwards.
30120                  */
30121                 year -= 1 + (diff_days - 1) / 366;  /* conservative */
30122         }
30123 }
30124
30125 /* Given a (year, month, day-within-month) triple, compute day number.
30126  * The input triple is un-normalized and may contain non-finite values.
30127  */
30128 DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day) {
30129         duk_int_t day_num;
30130         duk_bool_t is_leap;
30131         duk_small_int_t i, n;
30132
30133         /* Assume that year, month, day are all coerced to whole numbers.
30134          * They may also be NaN or infinity, in which case this function
30135          * must return NaN or infinity to ensure time value becomes NaN.
30136          * If 'day' is NaN, the final return will end up returning a NaN,
30137          * so it doesn't need to be checked here.
30138          */
30139
30140         if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) {
30141                 return DUK_DOUBLE_NAN;
30142         }
30143
30144         year += DUK_FLOOR(month / 12.0);
30145
30146         month = DUK_FMOD(month, 12.0);
30147         if (month < 0.0) {
30148                 /* handle negative values */
30149                 month += 12.0;
30150         }
30151
30152         /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but
30153          * does not normalize the day-of-month (nor check whether or not
30154          * it is finite) because it's not necessary for finding the day
30155          * number which matches the (year,month) pair.
30156          *
30157          * We assume that duk__day_from_year() is exact here.
30158          *
30159          * Without an explicit infinity / NaN check in the beginning,
30160          * day_num would be a bogus integer here.
30161          *
30162          * It's possible for 'year' to be out of integer range here.
30163          * If so, we need to return NaN without integer overflow.
30164          * This fixes test-bug-setyear-overflow.js.
30165          */
30166
30167         if (!duk_bi_date_year_in_valid_range(year)) {
30168                 DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid integer overflow: %lf", (double) year));
30169                 return DUK_DOUBLE_NAN;
30170         }
30171         day_num = duk__day_from_year((duk_int_t) year);
30172         is_leap = duk_bi_date_is_leap_year((duk_int_t) year);
30173
30174         n = (duk_small_int_t) month;
30175         for (i = 0; i < n; i++) {
30176                 day_num += duk__days_in_month[i];
30177                 if (i == 1 && is_leap) {
30178                         day_num++;
30179                 }
30180         }
30181
30182         /* If 'day' is NaN, returns NaN. */
30183         return (duk_double_t) day_num + day;
30184 }
30185
30186 /* Split time value into parts.  The time value may contain fractions (it may
30187  * come from duk_time_to_components() API call) which are truncated.  Possible
30188  * local time adjustment has already been applied when reading the time value.
30189  */
30190 DUK_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) {
30191         duk_double_t d1, d2;
30192         duk_int_t t1, t2;
30193         duk_int_t day_since_epoch;
30194         duk_int_t year;  /* does not fit into 16 bits */
30195         duk_small_int_t day_in_year;
30196         duk_small_int_t month;
30197         duk_small_int_t day;
30198         duk_small_int_t dim;
30199         duk_int_t jan1_since_epoch;
30200         duk_small_int_t jan1_weekday;
30201         duk_int_t equiv_year;
30202         duk_small_uint_t i;
30203         duk_bool_t is_leap;
30204         duk_small_int_t arridx;
30205
30206         DUK_ASSERT(DUK_ISFINITE(d));    /* caller checks */
30207         d = DUK_FLOOR(d);  /* remove fractions if present */
30208         DUK_ASSERT(DUK_FLOOR(d) == d);
30209
30210         /* The timevalue must be in valid ECMAScript range, but since a local
30211          * time offset can be applied, we need to allow a +/- 24h leeway to
30212          * the value.  In other words, although the UTC time is within the
30213          * ECMAScript range, the local part values can be just outside of it.
30214          */
30215         DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
30216         DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
30217
30218         /* These computations are guaranteed to be exact for the valid
30219          * E5 time value range, assuming milliseconds without fractions.
30220          */
30221         d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
30222         if (d1 < 0.0) {
30223                 /* deal with negative values */
30224                 d1 += (duk_double_t) DUK_DATE_MSEC_DAY;
30225         }
30226         d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY));
30227         DUK_ASSERT(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1 == d);
30228         /* now expected to fit into a 32-bit integer */
30229         t1 = (duk_int_t) d1;
30230         t2 = (duk_int_t) d2;
30231         day_since_epoch = t2;
30232         DUK_ASSERT((duk_double_t) t1 == d1);
30233         DUK_ASSERT((duk_double_t) t2 == d2);
30234
30235         /* t1 = milliseconds within day (fits 32 bit)
30236          * t2 = day number from epoch (fits 32 bit, may be negative)
30237          */
30238
30239         parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
30240         parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60;
30241         parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60;
30242         parts[DUK_DATE_IDX_HOUR] = t1;
30243         DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999);
30244         DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59);
30245         DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59);
30246         DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23);
30247
30248         DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld",
30249                              (double) d, (double) d1, (double) d2, (long) t1, (long) t2,
30250                              (long) parts[DUK_DATE_IDX_HOUR],
30251                              (long) parts[DUK_DATE_IDX_MINUTE],
30252                              (long) parts[DUK_DATE_IDX_SECOND],
30253                              (long) parts[DUK_DATE_IDX_MILLISECOND]));
30254
30255         /* This assert depends on the input parts representing time inside
30256          * the ECMAScript range.
30257          */
30258         DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0);
30259         parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7;  /* E5.1 Section 15.9.1.6 */
30260         DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6);
30261
30262         year = duk__year_from_day(t2, &day_in_year);
30263         day = day_in_year;
30264         is_leap = duk_bi_date_is_leap_year(year);
30265         for (month = 0; month < 12; month++) {
30266                 dim = duk__days_in_month[month];
30267                 if (month == 1 && is_leap) {
30268                         dim++;
30269                 }
30270                 DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld",
30271                                      (long) month, (long) dim, (long) day));
30272                 if (day < dim) {
30273                         break;
30274                 }
30275                 day -= dim;
30276         }
30277         DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month));
30278         DUK_ASSERT(month >= 0 && month <= 11);
30279         DUK_ASSERT(day >= 0 && day <= 31);
30280
30281         /* Equivalent year mapping, used to avoid DST trouble when platform
30282          * may fail to provide reasonable DST answers for dates outside the
30283          * ordinary range (e.g. 1970-2038).  An equivalent year has the same
30284          * leap-year-ness as the original year and begins on the same weekday
30285          * (Jan 1).
30286          *
30287          * The year 2038 is avoided because there seem to be problems with it
30288          * on some platforms.  The year 1970 is also avoided as there were
30289          * practical problems with it; an equivalent year is used for it too,
30290          * which breaks some DST computations for 1970 right now, see e.g.
30291          * test-bi-date-tzoffset-brute-fi.js.
30292          */
30293         if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) {
30294                 DUK_ASSERT(is_leap == 0 || is_leap == 1);
30295
30296                 jan1_since_epoch = day_since_epoch - day_in_year;  /* day number for Jan 1 since epoch */
30297                 DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0);
30298                 jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7;  /* E5.1 Section 15.9.1.6 */
30299                 DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6);
30300                 arridx = jan1_weekday;
30301                 if (is_leap) {
30302                         arridx += 7;
30303                 }
30304                 DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t)));
30305
30306                 equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970;
30307                 year = equiv_year;
30308                 DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, "
30309                                      "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld",
30310                                      (long) year, (long) day_in_year, (long) day_since_epoch,
30311                                      (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year));
30312         }
30313
30314         parts[DUK_DATE_IDX_YEAR] = year;
30315         parts[DUK_DATE_IDX_MONTH] = month;
30316         parts[DUK_DATE_IDX_DAY] = day;
30317
30318         if (flags & DUK_DATE_FLAG_ONEBASED) {
30319                 parts[DUK_DATE_IDX_MONTH]++;  /* zero-based -> one-based */
30320                 parts[DUK_DATE_IDX_DAY]++;    /* -""- */
30321         }
30322
30323         if (dparts != NULL) {
30324                 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
30325                         dparts[i] = (duk_double_t) parts[i];
30326                 }
30327         }
30328 }
30329
30330 /* Compute time value from (double) parts.  The parts can be either UTC
30331  * or local time; if local, they need to be (conceptually) converted into
30332  * UTC time.  The parts may represent valid or invalid time, and may be
30333  * wildly out of range (but may cancel each other and still come out in
30334  * the valid Date range).
30335  */
30336 DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags) {
30337 #if defined(DUK_USE_PARANOID_DATE_COMPUTATION)
30338         /* See comments below on MakeTime why these are volatile. */
30339         volatile duk_double_t tmp_time;
30340         volatile duk_double_t tmp_day;
30341         volatile duk_double_t d;
30342 #else
30343         duk_double_t tmp_time;
30344         duk_double_t tmp_day;
30345         duk_double_t d;
30346 #endif
30347         duk_small_uint_t i;
30348         duk_int_t tzoff, tzoffprev1, tzoffprev2;
30349
30350         /* Expects 'this' at top of stack on entry. */
30351
30352         /* Coerce all finite parts with ToInteger().  ToInteger() must not
30353          * be called for NaN/Infinity because it will convert e.g. NaN to
30354          * zero.  If ToInteger() has already been called, this has no side
30355          * effects and is idempotent.
30356          *
30357          * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind
30358          * issues if the value is uninitialized.
30359          */
30360         for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) {
30361                 /* SCANBUILD: scan-build complains here about assigned value
30362                  * being garbage or undefined.  This is correct but operating
30363                  * on undefined values has no ill effect and is ignored by the
30364                  * caller in the case where this happens.
30365                  */
30366                 d = dparts[i];
30367                 if (DUK_ISFINITE(d)) {
30368                         dparts[i] = duk_js_tointeger_number(d);
30369                 }
30370         }
30371
30372         /* Use explicit steps in computation to try to ensure that
30373          * computation happens with intermediate results coerced to
30374          * double values (instead of using something more accurate).
30375          * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
30376          * rules (= ECMAScript '+' and '*' operators).
30377          *
30378          * Without 'volatile' even this approach fails on some platform
30379          * and compiler combinations.  For instance, gcc 4.8.1 on Ubuntu
30380          * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js
30381          * would fail because of some optimizations when computing tmp_time
30382          * (MakeTime below).  Adding 'volatile' to tmp_time solved this
30383          * particular problem (annoyingly, also adding debug prints or
30384          * running the executable under valgrind hides it).
30385          */
30386
30387         /* MakeTime */
30388         tmp_time = 0.0;
30389         tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR);
30390         tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE);
30391         tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND);
30392         tmp_time += dparts[DUK_DATE_IDX_MILLISECOND];
30393
30394         /* MakeDay */
30395         tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]);
30396
30397         /* MakeDate */
30398         d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time;
30399
30400         DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf",
30401                              (double) tmp_time, (double) tmp_day, (double) d));
30402
30403         /* Optional UTC conversion. */
30404         if (flags & DUK_DATE_FLAG_LOCALTIME) {
30405                 /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a
30406                  * time value computed from UTC parts.  At this point we only
30407                  * have 'd' which is a time value computed from local parts, so
30408                  * it is off by the UTC-to-local time offset which we don't know
30409                  * yet.  The current solution for computing the UTC-to-local
30410                  * time offset is to iterate a few times and detect a fixed
30411                  * point or a two-cycle loop (or a sanity iteration limit),
30412                  * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js.
30413                  *
30414                  * E5.1 Section 15.9.1.9:
30415                  * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
30416                  *
30417                  * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0.
30418                  */
30419
30420 #if 0
30421                 /* Old solution: don't iterate, incorrect */
30422                 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
30423                 DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", (long) tzoff));
30424                 d -= tzoff * 1000L;
30425                 DUK_UNREF(tzoffprev1);
30426                 DUK_UNREF(tzoffprev2);
30427 #endif
30428
30429                 /* Iteration solution */
30430                 tzoff = 0;
30431                 tzoffprev1 = 999999999L;  /* invalid value which never matches */
30432                 for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) {
30433                         tzoffprev2 = tzoffprev1;
30434                         tzoffprev1 = tzoff;
30435                         tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L);
30436                         DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld",
30437                                              (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
30438                         if (tzoff == tzoffprev1) {
30439                                 DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
30440                                                      (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
30441                                 break;
30442                         } else if (tzoff == tzoffprev2) {
30443                                 /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js.
30444                                  * In these cases, favor a higher tzoffset to get a consistent
30445                                  * result which is independent of iteration count.  Not sure if
30446                                  * this is a generically correct solution.
30447                                  */
30448                                 DUK_DDD(DUK_DDDPRINT("tzoffset iteration two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
30449                                                      (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
30450                                 if (tzoffprev1 > tzoff) {
30451                                         tzoff = tzoffprev1;
30452                                 }
30453                                 break;
30454                         }
30455                 }
30456                 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld", (long) tzoff));
30457                 d -= tzoff * 1000L;
30458         }
30459
30460         /* TimeClip(), which also handles Infinity -> NaN conversion */
30461         d = duk__timeclip(d);
30462
30463         return d;
30464 }
30465
30466 /*
30467  *  API oriented helpers
30468  */
30469
30470 /* Push 'this' binding, check that it is a Date object; then push the
30471  * internal time value.  At the end, stack is: [ ... this timeval ].
30472  * Returns the time value.  Local time adjustment is done if requested.
30473  */
30474 DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_hthread *thr, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
30475         duk_hobject *h;
30476         duk_double_t d;
30477         duk_int_t tzoffset = 0;
30478
30479         duk_push_this(thr);
30480         h = duk_get_hobject(thr, -1);  /* XXX: getter with class check, useful in built-ins */
30481         if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
30482                 DUK_ERROR_TYPE(thr, "expected Date");
30483                 DUK_WO_NORETURN(return 0.0;);
30484         }
30485
30486         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
30487         d = duk_to_number_m1(thr);
30488         duk_pop(thr);
30489
30490         if (DUK_ISNAN(d)) {
30491                 if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
30492                         d = 0.0;
30493                 }
30494                 if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) {
30495                         DUK_ERROR_RANGE(thr, "Invalid Date");
30496                         DUK_WO_NORETURN(return 0.0;);
30497                 }
30498         }
30499         /* if no NaN handling flag, may still be NaN here, but not Inf */
30500         DUK_ASSERT(!DUK_ISINF(d));
30501
30502         if (flags & DUK_DATE_FLAG_LOCALTIME) {
30503                 /* Note: DST adjustment is determined using UTC time.
30504                  * If 'd' is NaN, tzoffset will be 0.
30505                  */
30506                 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);  /* seconds */
30507                 d += tzoffset * 1000L;
30508         }
30509         if (out_tzoffset) {
30510                 *out_tzoffset = tzoffset;
30511         }
30512
30513         /* [ ... this ] */
30514         return d;
30515 }
30516
30517 DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_hthread *thr, duk_small_uint_t flags) {
30518         return duk__push_this_get_timeval_tzoffset(thr, flags, NULL);
30519 }
30520
30521 /* Set timeval to 'this' from dparts, push the new time value onto the
30522  * value stack and return 1 (caller can then tail call us).  Expects
30523  * the value stack to contain 'this' on the stack top.
30524  */
30525 DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_hthread *thr, duk_double_t *dparts, duk_small_uint_t flags) {
30526         duk_double_t d;
30527
30528         /* [ ... this ] */
30529
30530         d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
30531         duk_push_number(thr, d);  /* -> [ ... this timeval_new ] */
30532         duk_dup_top(thr);         /* -> [ ... this timeval_new timeval_new ] */
30533         duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE);
30534
30535         /* stack top: new time value, return 1 to allow tail calls */
30536         return 1;
30537 }
30538
30539 /* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */
30540 DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags, duk_uint8_t *out_buf) {
30541         char yearstr[8];   /* "-123456\0" */
30542         char tzstr[8];     /* "+11:22\0" */
30543         char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE;
30544
30545         DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
30546         DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
30547         DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && parts[DUK_DATE_IDX_YEAR] <= 999999);
30548
30549         /* Note: %06d for positive value, %07d for negative value to include
30550          * sign and 6 digits.
30551          */
30552         DUK_SNPRINTF(yearstr,
30553                      sizeof(yearstr),
30554                      (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] <= 9999) ? "%04ld" :
30555                             ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : "%07ld"),
30556                      (long) parts[DUK_DATE_IDX_YEAR]);
30557         yearstr[sizeof(yearstr) - 1] = (char) 0;
30558
30559         if (flags & DUK_DATE_FLAG_LOCALTIME) {
30560                 /* tzoffset seconds are dropped; 16 bits suffice for
30561                  * time offset in minutes
30562                  */
30563                 const char *fmt;
30564                 duk_small_int_t tmp, arg_hours, arg_minutes;
30565
30566                 if (tzoffset >= 0) {
30567                         tmp = tzoffset;
30568                         fmt = "+%02d:%02d";
30569                 } else {
30570                         tmp = -tzoffset;
30571                         fmt = "-%02d:%02d";
30572                 }
30573                 tmp = tmp / 60;
30574                 arg_hours = tmp / 60;
30575                 arg_minutes = tmp % 60;
30576                 DUK_ASSERT(arg_hours <= 24);  /* Even less is actually guaranteed for a valid tzoffset. */
30577                 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. */
30578
30579                 DUK_SNPRINTF(tzstr, sizeof(tzstr), fmt, (int) arg_hours, (int) arg_minutes);
30580                 tzstr[sizeof(tzstr) - 1] = (char) 0;
30581         } else {
30582                 tzstr[0] = DUK_ASC_UC_Z;
30583                 tzstr[1] = (char) 0;
30584         }
30585
30586         /* Unlike year, the other parts fit into 16 bits so %d format
30587          * is portable.
30588          */
30589         if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
30590                 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s",
30591                             (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep,
30592                             (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
30593                             (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr);
30594         } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
30595                 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d",
30596                             (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]);
30597         } else {
30598                 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
30599                 DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s",
30600                             (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
30601                             (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND],
30602                             (const char *) tzstr);
30603         }
30604 }
30605
30606 /* Helper for string conversion calls: check 'this' binding, get the
30607  * internal time value, and format date and/or time in a few formats.
30608  * Return value allows tail calls.
30609  */
30610 DUK_LOCAL duk_ret_t duk__to_string_helper(duk_hthread *thr, duk_small_uint_t flags) {
30611         duk_double_t d;
30612         duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
30613         duk_int_t tzoffset;  /* seconds, doesn't fit into 16 bits */
30614         duk_bool_t rc;
30615         duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE];
30616
30617         DUK_UNREF(rc);  /* unreferenced with some options */
30618
30619         d = duk__push_this_get_timeval_tzoffset(thr, flags, &tzoffset);
30620         if (DUK_ISNAN(d)) {
30621                 duk_push_hstring_stridx(thr, DUK_STRIDX_INVALID_DATE);
30622                 return 1;
30623         }
30624         DUK_ASSERT(DUK_ISFINITE(d));
30625
30626         /* formatters always get one-based month/day-of-month */
30627         duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED);
30628         DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
30629         DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
30630
30631         if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) {
30632                 /* try locale specific formatter; if it refuses to format the
30633                  * string, fall back to an ISO 8601 formatted value in local
30634                  * time.
30635                  */
30636 #if defined(DUK_USE_DATE_FORMAT_STRING)
30637                 /* Contract, either:
30638                  * - Push string to value stack and return 1
30639                  * - Don't push anything and return 0
30640                  */
30641
30642                 rc = DUK_USE_DATE_FORMAT_STRING(thr, parts, tzoffset, flags);
30643                 if (rc != 0) {
30644                         return 1;
30645                 }
30646 #else
30647                 /* No locale specific formatter; this is OK, we fall back
30648                  * to ISO 8601.
30649                  */
30650 #endif
30651         }
30652
30653         /* Different calling convention than above used because the helper
30654          * is shared.
30655          */
30656         duk__format_parts_iso8601(parts, tzoffset, flags, buf);
30657         duk_push_string(thr, (const char *) buf);
30658         return 1;
30659 }
30660
30661 /* Helper for component getter calls: check 'this' binding, get the
30662  * internal time value, split it into parts (either as UTC time or
30663  * local time), push a specified component as a return value to the
30664  * value stack and return 1 (caller can then tail call us).
30665  */
30666 DUK_LOCAL duk_ret_t duk__get_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_idx) {
30667         duk_double_t d;
30668         duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
30669         duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT);  /* unpack args */
30670
30671         DUK_ASSERT_DISABLE(idx_part >= 0);  /* unsigned */
30672         DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
30673
30674         d = duk__push_this_get_timeval(thr, flags_and_idx);
30675         if (DUK_ISNAN(d)) {
30676                 duk_push_nan(thr);
30677                 return 1;
30678         }
30679         DUK_ASSERT(DUK_ISFINITE(d));
30680
30681         duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx);  /* no need to mask idx portion */
30682
30683         /* Setter APIs detect special year numbers (0...99) and apply a +1900
30684          * only in certain cases.  The legacy getYear() getter applies -1900
30685          * unconditionally.
30686          */
30687         duk_push_int(thr, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
30688         return 1;
30689 }
30690
30691 /* Helper for component setter calls: check 'this' binding, get the
30692  * internal time value, split it into parts (either as UTC time or
30693  * local time), modify one or more components as specified, recompute
30694  * the time value, set it as the internal value.  Finally, push the
30695  * new time value as a return value to the value stack and return 1
30696  * (caller can then tail call us).
30697  */
30698 DUK_LOCAL duk_ret_t duk__set_part_helper(duk_hthread *thr, duk_small_uint_t flags_and_maxnargs) {
30699         duk_double_t d;
30700         duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
30701         duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
30702         duk_idx_t nargs;
30703         duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> DUK_DATE_FLAG_VALUE_SHIFT);  /* unpack args */
30704         duk_small_uint_t idx_first, idx;
30705         duk_small_uint_t i;
30706
30707         nargs = duk_get_top(thr);
30708         d = duk__push_this_get_timeval(thr, flags_and_maxnargs);
30709         DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
30710
30711         if (DUK_ISFINITE(d)) {
30712                 duk_bi_date_timeval_to_parts(d, parts, dparts, flags_and_maxnargs);
30713         } else {
30714                 /* NaN timevalue: we need to coerce the arguments, but
30715                  * the resulting internal timestamp needs to remain NaN.
30716                  * This works but is not pretty: parts and dparts will
30717                  * be partially uninitialized, but we only write to them.
30718                  */
30719         }
30720
30721         /*
30722          *  Determining which datetime components to overwrite based on
30723          *  stack arguments is a bit complicated, but important to factor
30724          *  out from setters themselves for compactness.
30725          *
30726          *  If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type:
30727          *
30728          *   1 -> millisecond
30729          *   2 -> second, [millisecond]
30730          *   3 -> minute, [second], [millisecond]
30731          *   4 -> hour, [minute], [second], [millisecond]
30732          *
30733          *  Else:
30734          *
30735          *   1 -> date
30736          *   2 -> month, [date]
30737          *   3 -> year, [month], [date]
30738          *
30739          *  By comparing nargs and maxnargs (and flags) we know which
30740          *  components to override.  We rely on part index ordering.
30741          */
30742
30743         if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) {
30744                 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4);
30745                 idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1);
30746         } else {
30747                 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3);
30748                 idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1);
30749         }
30750         DUK_ASSERT_DISABLE(idx_first >= 0);  /* unsigned */
30751         DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS);
30752
30753         for (i = 0; i < maxnargs; i++) {
30754                 if ((duk_idx_t) i >= nargs) {
30755                         /* no argument given -> leave components untouched */
30756                         break;
30757                 }
30758                 idx = idx_first + i;
30759                 DUK_ASSERT_DISABLE(idx >= 0);  /* unsigned */
30760                 DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
30761
30762                 if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
30763                         duk__twodigit_year_fixup(thr, (duk_idx_t) i);
30764                 }
30765
30766                 dparts[idx] = duk_to_number(thr, (duk_idx_t) i);
30767
30768                 if (idx == DUK_DATE_IDX_DAY) {
30769                         /* Day-of-month is one-based in the API, but zero-based
30770                          * internally, so fix here.  Note that month is zero-based
30771                          * both in the API and internally.
30772                          */
30773                         /* SCANBUILD: complains about use of uninitialized values.
30774                          * The complaint is correct, but operating in undefined
30775                          * values here is intentional in some cases and the caller
30776                          * ignores the results.
30777                          */
30778                         dparts[idx] -= 1.0;
30779                 }
30780         }
30781
30782         /* Leaves new timevalue on stack top and returns 1, which is correct
30783          * for part setters.
30784          */
30785         if (DUK_ISFINITE(d)) {
30786                 return duk__set_this_timeval_from_dparts(thr, dparts, flags_and_maxnargs);
30787         } else {
30788                 /* Internal timevalue is already NaN, so don't touch it. */
30789                 duk_push_nan(thr);
30790                 return 1;
30791         }
30792 }
30793
30794 /* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
30795  * 1900 and replace value at idx_val.
30796  */
30797 DUK_LOCAL void duk__twodigit_year_fixup(duk_hthread *thr, duk_idx_t idx_val) {
30798         duk_double_t d;
30799
30800         /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
30801          * might not generate better code due to casting.
30802          */
30803
30804         /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
30805         duk_to_number(thr, idx_val);
30806         if (duk_is_nan(thr, idx_val)) {
30807                 return;
30808         }
30809         duk_dup(thr, idx_val);
30810         duk_to_int(thr, -1);
30811         d = duk_get_number(thr, -1);  /* get as double to handle huge numbers correctly */
30812         if (d >= 0.0 && d <= 99.0) {
30813                 d += 1900.0;
30814                 duk_push_number(thr, d);
30815                 duk_replace(thr, idx_val);
30816         }
30817         duk_pop(thr);
30818 }
30819
30820 /* Set datetime parts from stack arguments, defaulting any missing values.
30821  * Day-of-week is not set; it is not required when setting the time value.
30822  */
30823 DUK_LOCAL void duk__set_parts_from_args(duk_hthread *thr, duk_double_t *dparts, duk_idx_t nargs) {
30824         duk_double_t d;
30825         duk_small_uint_t i;
30826         duk_small_uint_t idx;
30827
30828         /* Causes a ToNumber() coercion, but doesn't break coercion order since
30829          * year is coerced first anyway.
30830          */
30831         duk__twodigit_year_fixup(thr, 0);
30832
30833         /* There are at most 7 args, but we use 8 here so that also
30834          * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
30835          * for any Valgrind gripes later.
30836          */
30837         for (i = 0; i < 8; i++) {
30838                 /* Note: rely on index ordering */
30839                 idx = DUK_DATE_IDX_YEAR + i;
30840                 if ((duk_idx_t) i < nargs) {
30841                         d = duk_to_number(thr, (duk_idx_t) i);
30842                         if (idx == DUK_DATE_IDX_DAY) {
30843                                 /* Convert day from one-based to zero-based (internal).  This may
30844                                  * cause the day part to be negative, which is OK.
30845                                  */
30846                                 d -= 1.0;
30847                         }
30848                 } else {
30849                         /* All components default to 0 except day-of-month which defaults
30850                          * to 1.  However, because our internal day-of-month is zero-based,
30851                          * it also defaults to zero here.
30852                          */
30853                         d = 0.0;
30854                 }
30855                 dparts[idx] = d;
30856         }
30857
30858         DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf",
30859                              (double) dparts[0], (double) dparts[1],
30860                              (double) dparts[2], (double) dparts[3],
30861                              (double) dparts[4], (double) dparts[5],
30862                              (double) dparts[6], (double) dparts[7]));
30863 }
30864
30865 /*
30866  *  Indirect magic value lookup for Date methods.
30867  *
30868  *  Date methods don't put their control flags into the function magic value
30869  *  because they wouldn't fit into a LIGHTFUNC's magic field.  Instead, the
30870  *  magic value is set to an index pointing to the array of control flags
30871  *  below.
30872  *
30873  *  This must be kept in strict sync with genbuiltins.py!
30874  */
30875
30876 static duk_uint16_t duk__date_magics[] = {
30877         /* 0: toString */
30878         DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
30879
30880         /* 1: toDateString */
30881         DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME,
30882
30883         /* 2: toTimeString */
30884         DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
30885
30886         /* 3: toLocaleString */
30887         DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
30888
30889         /* 4: toLocaleDateString */
30890         DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
30891
30892         /* 5: toLocaleTimeString */
30893         DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
30894
30895         /* 6: toUTCString */
30896         DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME,
30897
30898         /* 7: toISOString */
30899         DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T,
30900
30901         /* 8: getFullYear */
30902         DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
30903
30904         /* 9: getUTCFullYear */
30905         0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
30906
30907         /* 10: getMonth */
30908         DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
30909
30910         /* 11: getUTCMonth */
30911         0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
30912
30913         /* 12: getDate */
30914         DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
30915
30916         /* 13: getUTCDate */
30917         DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
30918
30919         /* 14: getDay */
30920         DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
30921
30922         /* 15: getUTCDay */
30923         0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
30924
30925         /* 16: getHours */
30926         DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
30927
30928         /* 17: getUTCHours */
30929         0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
30930
30931         /* 18: getMinutes */
30932         DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
30933
30934         /* 19: getUTCMinutes */
30935         0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
30936
30937         /* 20: getSeconds */
30938         DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
30939
30940         /* 21: getUTCSeconds */
30941         0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
30942
30943         /* 22: getMilliseconds */
30944         DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
30945
30946         /* 23: getUTCMilliseconds */
30947         0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
30948
30949         /* 24: setMilliseconds */
30950         DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
30951
30952         /* 25: setUTCMilliseconds */
30953         DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
30954
30955         /* 26: setSeconds */
30956         DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
30957
30958         /* 27: setUTCSeconds */
30959         DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
30960
30961         /* 28: setMinutes */
30962         DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
30963
30964         /* 29: setUTCMinutes */
30965         DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
30966
30967         /* 30: setHours */
30968         DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
30969
30970         /* 31: setUTCHours */
30971         DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
30972
30973         /* 32: setDate */
30974         DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
30975
30976         /* 33: setUTCDate */
30977         0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
30978
30979         /* 34: setMonth */
30980         DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
30981
30982         /* 35: setUTCMonth */
30983         0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
30984
30985         /* 36: setFullYear */
30986         DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
30987
30988         /* 37: setUTCFullYear */
30989         DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
30990
30991         /* 38: getYear */
30992         DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
30993
30994         /* 39: setYear */
30995         DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
30996 };
30997
30998 DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_hthread *thr) {
30999         duk_small_uint_t magicidx = (duk_small_uint_t) duk_get_current_magic(thr);
31000         DUK_ASSERT(magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
31001         return (duk_small_uint_t) duk__date_magics[magicidx];
31002 }
31003
31004 #if defined(DUK_USE_DATE_BUILTIN)
31005 /*
31006  *  Constructor calls
31007  */
31008
31009 DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_hthread *thr) {
31010         duk_idx_t nargs = duk_get_top(thr);
31011         duk_bool_t is_cons = duk_is_constructor_call(thr);
31012         duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
31013         duk_double_t d;
31014
31015         DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
31016
31017         (void) duk_push_object_helper(thr,
31018                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
31019                                       DUK_HOBJECT_FLAG_FASTREFS |
31020                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
31021                                       DUK_BIDX_DATE_PROTOTYPE);
31022
31023         /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
31024          * is mutable.
31025          */
31026
31027         if (nargs == 0 || !is_cons) {
31028                 d = duk__timeclip(duk_time_get_ecmascript_time_nofrac(thr));
31029                 duk_push_number(thr, d);
31030                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
31031                 if (!is_cons) {
31032                         /* called as a normal function: return new Date().toString() */
31033                         duk_to_string(thr, -1);
31034                 }
31035                 return 1;
31036         } else if (nargs == 1) {
31037                 const char *str;
31038                 duk_to_primitive(thr, 0, DUK_HINT_NONE);
31039                 str = duk_get_string_notsymbol(thr, 0);
31040                 if (str) {
31041                         duk__parse_string(thr, str);
31042                         duk_replace(thr, 0);  /* may be NaN */
31043                 }
31044                 d = duk__timeclip(duk_to_number(thr, 0));  /* symbols fail here */
31045                 duk_push_number(thr, d);
31046                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
31047                 return 1;
31048         }
31049
31050         duk__set_parts_from_args(thr, dparts, nargs);
31051
31052         /* Parts are in local time, convert when setting. */
31053
31054         (void) duk__set_this_timeval_from_dparts(thr, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/);  /* -> [ ... this timeval ] */
31055         duk_pop(thr);  /* -> [ ... this ] */
31056         return 1;
31057 }
31058
31059 DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_hthread *thr) {
31060         return duk__parse_string(thr, duk_to_string(thr, 0));
31061 }
31062
31063 DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_hthread *thr) {
31064         duk_idx_t nargs = duk_get_top(thr);
31065         duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
31066         duk_double_t d;
31067
31068         /* Behavior for nargs < 2 is implementation dependent: currently we'll
31069          * set a NaN time value (matching V8 behavior) in this case.
31070          */
31071
31072         if (nargs < 2) {
31073                 duk_push_nan(thr);
31074         } else {
31075                 duk__set_parts_from_args(thr, dparts, nargs);
31076                 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
31077                 duk_push_number(thr, d);
31078         }
31079         return 1;
31080 }
31081
31082 DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_hthread *thr) {
31083         duk_double_t d;
31084
31085         d = duk_time_get_ecmascript_time_nofrac(thr);
31086         DUK_ASSERT(duk__timeclip(d) == d);  /* TimeClip() should never be necessary */
31087         duk_push_number(thr, d);
31088         return 1;
31089 }
31090
31091 /*
31092  *  String/JSON conversions
31093  *
31094  *  Human readable conversions are now basically ISO 8601 with a space
31095  *  (instead of 'T') as the date/time separator.  This is a good baseline
31096  *  and is platform independent.
31097  *
31098  *  A shared native helper to provide many conversions.  Magic value contains
31099  *  a set of flags.  The helper provides:
31100  *
31101  *    toString()
31102  *    toDateString()
31103  *    toTimeString()
31104  *    toLocaleString()
31105  *    toLocaleDateString()
31106  *    toLocaleTimeString()
31107  *    toUTCString()
31108  *    toISOString()
31109  *
31110  *  Notes:
31111  *
31112  *    - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
31113  *      required to be the same ECMAScript function object (!), so it is
31114  *      omitted from here.
31115  *
31116  *    - Date.prototype.toUTCString(): E5.1 specification does not require a
31117  *      specific format, but result should be human readable.  The
31118  *      specification suggests using ISO 8601 format with a space (instead
31119  *      of 'T') separator if a more human readable format is not available.
31120  *
31121  *    - Date.prototype.toISOString(): unlike other conversion functions,
31122  *      toISOString() requires a RangeError for invalid date values.
31123  */
31124
31125 DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_hthread *thr) {
31126         duk_small_uint_t flags = duk__date_get_indirect_magic(thr);
31127         return duk__to_string_helper(thr, flags);
31128 }
31129
31130 DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_hthread *thr) {
31131         /* This native function is also used for Date.prototype.getTime()
31132          * as their behavior is identical.
31133          */
31134
31135         duk_double_t d = duk__push_this_get_timeval(thr, 0 /*flags*/);  /* -> [ this ] */
31136         DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
31137         duk_push_number(thr, d);
31138         return 1;
31139 }
31140
31141 DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_hthread *thr) {
31142         /* Note: toJSON() is a generic function which works even if 'this'
31143          * is not a Date.  The sole argument is ignored.
31144          */
31145
31146         duk_push_this(thr);
31147         duk_to_object(thr, -1);
31148
31149         duk_dup_top(thr);
31150         duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
31151         if (duk_is_number(thr, -1)) {
31152                 duk_double_t d = duk_get_number(thr, -1);
31153                 if (!DUK_ISFINITE(d)) {
31154                         duk_push_null(thr);
31155                         return 1;
31156                 }
31157         }
31158         duk_pop(thr);
31159
31160         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_ISO_STRING);
31161         duk_dup_m2(thr);  /* -> [ O toIsoString O ] */
31162         duk_call_method(thr, 0);
31163         return 1;
31164 }
31165
31166 /*
31167  *  Getters.
31168  *
31169  *  Implementing getters is quite easy.  The internal time value is either
31170  *  NaN, or represents milliseconds (without fractions) from Jan 1, 1970.
31171  *  The internal time value can be converted to integer parts, and each
31172  *  part will be normalized and will fit into a 32-bit signed integer.
31173  *
31174  *  A shared native helper to provide all getters.  Magic value contains
31175  *  a set of flags and also packs the date component index argument.  The
31176  *  helper provides:
31177  *
31178  *    getFullYear()
31179  *    getUTCFullYear()
31180  *    getMonth()
31181  *    getUTCMonth()
31182  *    getDate()
31183  *    getUTCDate()
31184  *    getDay()
31185  *    getUTCDay()
31186  *    getHours()
31187  *    getUTCHours()
31188  *    getMinutes()
31189  *    getUTCMinutes()
31190  *    getSeconds()
31191  *    getUTCSeconds()
31192  *    getMilliseconds()
31193  *    getUTCMilliseconds()
31194  *    getYear()
31195  *
31196  *  Notes:
31197  *
31198  *    - Date.prototype.getDate(): 'date' means day-of-month, and is
31199  *      zero-based in internal calculations but public API expects it to
31200  *      be one-based.
31201  *
31202  *    - Date.prototype.getTime() and Date.prototype.valueOf() have identical
31203  *      behavior.  They have separate function objects, but share the same C
31204  *      function (duk_bi_date_prototype_value_of).
31205  */
31206
31207 DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_hthread *thr) {
31208         duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(thr);
31209         return duk__get_part_helper(thr, flags_and_idx);
31210 }
31211
31212 DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_hthread *thr) {
31213         /*
31214          *  Return (t - LocalTime(t)) in minutes:
31215          *
31216          *    t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t))
31217          *                     = -(LocalTZA + DaylightSavingTA(t))
31218          *
31219          *  where DaylightSavingTA() is checked for time 't'.
31220          *
31221          *  Note that the sign of the result is opposite to common usage,
31222          *  e.g. for EE(S)T which normally is +2h or +3h from UTC, this
31223          *  function returns -120 or -180.
31224          *
31225          */
31226
31227         duk_double_t d;
31228         duk_int_t tzoffset;
31229
31230         /* Note: DST adjustment is determined using UTC time. */
31231         d = duk__push_this_get_timeval(thr, 0 /*flags*/);
31232         DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
31233         if (DUK_ISNAN(d)) {
31234                 duk_push_nan(thr);
31235         } else {
31236                 DUK_ASSERT(DUK_ISFINITE(d));
31237                 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
31238                 duk_push_int(thr, -tzoffset / 60);
31239         }
31240         return 1;
31241 }
31242
31243 /*
31244  *  Setters.
31245  *
31246  *  Setters are a bit more complicated than getters.  Component setters
31247  *  break down the current time value into its (normalized) component
31248  *  parts, replace one or more components with -unnormalized- new values,
31249  *  and the components are then converted back into a time value.  As an
31250  *  example of using unnormalized values:
31251  *
31252  *    var d = new Date(1234567890);
31253  *
31254  *  is equivalent to:
31255  *
31256  *    var d = new Date(0);
31257  *    d.setUTCMilliseconds(1234567890);
31258  *
31259  *  A shared native helper to provide almost all setters.  Magic value
31260  *  contains a set of flags and also packs the "maxnargs" argument.  The
31261  *  helper provides:
31262  *
31263  *    setMilliseconds()
31264  *    setUTCMilliseconds()
31265  *    setSeconds()
31266  *    setUTCSeconds()
31267  *    setMinutes()
31268  *    setUTCMinutes()
31269  *    setHours()
31270  *    setUTCHours()
31271  *    setDate()
31272  *    setUTCDate()
31273  *    setMonth()
31274  *    setUTCMonth()
31275  *    setFullYear()
31276  *    setUTCFullYear()
31277  *    setYear()
31278  *
31279  *  Notes:
31280  *
31281  *    - Date.prototype.setYear() (Section B addition): special year check
31282  *      is omitted.  NaN / Infinity will just flow through and ultimately
31283  *      result in a NaN internal time value.
31284  *
31285  *    - Date.prototype.setYear() does not have optional arguments for
31286  *      setting month and day-in-month (like setFullYear()), but we indicate
31287  *      'maxnargs' to be 3 to get the year written to the correct component
31288  *      index in duk__set_part_helper().  The function has nargs == 1, so only
31289  *      the year will be set regardless of actual argument count.
31290  */
31291
31292 DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_hthread *thr) {
31293         duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(thr);
31294         return duk__set_part_helper(thr, flags_and_maxnargs);
31295 }
31296
31297 DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_hthread *thr) {
31298         duk_double_t d;
31299
31300         (void) duk__push_this_get_timeval(thr, 0 /*flags*/); /* -> [ timeval this ] */
31301         d = duk__timeclip(duk_to_number(thr, 0));
31302         duk_push_number(thr, d);
31303         duk_dup_top(thr);
31304         duk_put_prop_stridx_short(thr, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
31305
31306         return 1;
31307 }
31308
31309 /*
31310  *  Misc.
31311  */
31312
31313 #if defined(DUK_USE_SYMBOL_BUILTIN)
31314 DUK_INTERNAL duk_ret_t duk_bi_date_prototype_toprimitive(duk_hthread *thr) {
31315         duk_size_t hintlen;
31316         const char *hintstr;
31317         duk_int_t hint;
31318
31319         /* Invokes OrdinaryToPrimitive() with suitable hint.  Note that the
31320          * method is generic, and works on non-Date arguments too.
31321          *
31322          * https://www.ecma-international.org/ecma-262/6.0/#sec-date.prototype-@@toprimitive
31323          */
31324
31325         duk_push_this(thr);
31326         duk_require_object(thr, -1);
31327         DUK_ASSERT_TOP(thr, 2);
31328
31329         hintstr = duk_require_lstring(thr, 0, &hintlen);
31330         if ((hintlen == 6 && DUK_STRCMP(hintstr, "string") == 0) ||
31331             (hintlen == 7 && DUK_STRCMP(hintstr, "default") == 0)) {
31332                 hint = DUK_HINT_STRING;
31333         } else if (hintlen == 6 && DUK_STRCMP(hintstr, "number") == 0) {
31334                 hint = DUK_HINT_NUMBER;
31335         } else {
31336                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
31337         }
31338
31339         duk_to_primitive_ordinary(thr, -1, hint);
31340         return 1;
31341 }
31342 #endif  /* DUK_USE_SYMBOL_BUILTIN */
31343
31344 #endif  /* DUK_USE_DATE_BUILTIN */
31345
31346 /* automatic undefs */
31347 #undef DUK__CF_ACCEPT
31348 #undef DUK__CF_ACCEPT_NUL
31349 #undef DUK__CF_NEG
31350 #undef DUK__DPRINT_DPARTS
31351 #undef DUK__DPRINT_PARTS
31352 #undef DUK__DPRINT_PARTS_AND_DPARTS
31353 #undef DUK__LOCAL_TZOFFSET_MAXITER
31354 #undef DUK__NUM_ISO8601_PARSER_PARTS
31355 #undef DUK__PACK_RULE
31356 #undef DUK__PI_DAY
31357 #undef DUK__PI_HOUR
31358 #undef DUK__PI_MILLISECOND
31359 #undef DUK__PI_MINUTE
31360 #undef DUK__PI_MONTH
31361 #undef DUK__PI_SECOND
31362 #undef DUK__PI_TZHOUR
31363 #undef DUK__PI_TZMINUTE
31364 #undef DUK__PI_YEAR
31365 #undef DUK__PM_DAY
31366 #undef DUK__PM_HOUR
31367 #undef DUK__PM_MILLISECOND
31368 #undef DUK__PM_MINUTE
31369 #undef DUK__PM_MONTH
31370 #undef DUK__PM_SECOND
31371 #undef DUK__PM_TZHOUR
31372 #undef DUK__PM_TZMINUTE
31373 #undef DUK__PM_YEAR
31374 #undef DUK__RULE_MASK_PART_SEP
31375 #undef DUK__SI_COLON
31376 #undef DUK__SI_MINUS
31377 #undef DUK__SI_NUL
31378 #undef DUK__SI_PERIOD
31379 #undef DUK__SI_PLUS
31380 #undef DUK__SI_SPACE
31381 #undef DUK__SI_T
31382 #undef DUK__SI_Z
31383 #undef DUK__SM_COLON
31384 #undef DUK__SM_MINUS
31385 #undef DUK__SM_NUL
31386 #undef DUK__SM_PERIOD
31387 #undef DUK__SM_PLUS
31388 #undef DUK__SM_SPACE
31389 #undef DUK__SM_T
31390 #undef DUK__SM_Z
31391 #undef DUK__UNPACK_RULE
31392 #undef DUK__WEEKDAY_MOD_ADDER
31393 #undef DUK__YEAR
31394 #line 1 "duk_bi_date_unix.c"
31395 /*
31396  *  Unix-like Date providers
31397  *
31398  *  Generally useful Unix / POSIX / ANSI Date providers.
31399  */
31400
31401 /* #include duk_internal.h -> already included */
31402
31403 /* The necessary #includes are in place in duk_config.h. */
31404
31405 /* Buffer sizes for some UNIX calls.  Larger than strictly necessary
31406  * to avoid Valgrind errors.
31407  */
31408 #define DUK__STRPTIME_BUF_SIZE  64
31409 #define DUK__STRFTIME_BUF_SIZE  64
31410
31411 #if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
31412 /* Get current ECMAScript time (= UNIX/Posix time, but in milliseconds). */
31413 DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(void) {
31414         struct timeval tv;
31415         duk_double_t d;
31416
31417         if (gettimeofday(&tv, NULL) != 0) {
31418                 DUK_D(DUK_DPRINT("gettimeofday() failed"));
31419                 return 0.0;
31420         }
31421
31422         /* As of Duktape 2.2.0 allow fractions. */
31423         d = ((duk_double_t) tv.tv_sec) * 1000.0 +
31424             ((duk_double_t) tv.tv_usec) / 1000.0;
31425
31426         return d;
31427 }
31428 #endif  /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
31429
31430 #if defined(DUK_USE_DATE_NOW_TIME)
31431 /* Not a very good provider: only full seconds are available. */
31432 DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(void) {
31433         time_t t;
31434
31435         t = time(NULL);
31436         if (t == (time_t) -1) {
31437                 DUK_D(DUK_DPRINT("time() failed"));
31438                 return 0.0;
31439         }
31440         return ((duk_double_t) t) * 1000.0;
31441 }
31442 #endif  /* DUK_USE_DATE_NOW_TIME */
31443
31444 #if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S)
31445 /* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
31446 DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
31447         time_t t, t1, t2;
31448         duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
31449         duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
31450         struct tm tms[2];
31451 #if defined(DUK_USE_DATE_TZO_GMTIME)
31452         struct tm *tm_ptr;
31453 #endif
31454
31455         /* For NaN/inf, the return value doesn't matter. */
31456         if (!DUK_ISFINITE(d)) {
31457                 return 0;
31458         }
31459
31460         /* If not within ECMAScript range, some integer time calculations
31461          * won't work correctly (and some asserts will fail), so bail out
31462          * if so.  This fixes test-bug-date-insane-setyear.js.  There is
31463          * a +/- 24h leeway in this range check to avoid a test262 corner
31464          * case documented in test-bug-date-timeval-edges.js.
31465          */
31466         if (!duk_bi_date_timeval_in_leeway_range(d)) {
31467                 DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows"));
31468                 return 0;
31469         }
31470
31471         /*
31472          *  This is a bit tricky to implement portably.  The result depends
31473          *  on the timestamp (specifically, DST depends on the timestamp).
31474          *  If e.g. UNIX APIs are used, they'll have portability issues with
31475          *  very small and very large years.
31476          *
31477          *  Current approach:
31478          *
31479          *  - Stay within portable UNIX limits by using equivalent year mapping.
31480          *    Avoid year 1970 and 2038 as some conversions start to fail, at
31481          *    least on some platforms.  Avoiding 1970 means that there are
31482          *    currently DST discrepancies for 1970.
31483          *
31484          *  - Create a UTC and local time breakdowns from 't'.  Then create
31485          *    a time_t using gmtime() and localtime() and compute the time
31486          *    difference between the two.
31487          *
31488          *  Equivalent year mapping (E5 Section 15.9.1.8):
31489          *
31490          *    If the host environment provides functionality for determining
31491          *    daylight saving time, the implementation of ECMAScript is free
31492          *    to map the year in question to an equivalent year (same
31493          *    leap-year-ness and same starting week day for the year) for which
31494          *    the host environment provides daylight saving time information.
31495          *    The only restriction is that all equivalent years should produce
31496          *    the same result.
31497          *
31498          *  This approach is quite reasonable but not entirely correct, e.g.
31499          *  the specification also states (E5 Section 15.9.1.8):
31500          *
31501          *    The implementation of ECMAScript should not try to determine
31502          *    whether the exact time was subject to daylight saving time, but
31503          *    just whether daylight saving time would have been in effect if
31504          *    the _current daylight saving time algorithm_ had been used at the
31505          *    time.  This avoids complications such as taking into account the
31506          *    years that the locale observed daylight saving time year round.
31507          *
31508          *  Since we rely on the platform APIs for conversions between local
31509          *  time and UTC, we can't guarantee the above.  Rather, if the platform
31510          *  has historical DST rules they will be applied.  This seems to be the
31511          *  general preferred direction in ECMAScript standardization (or at least
31512          *  implementations) anyway, and even the equivalent year mapping should
31513          *  be disabled if the platform is known to handle DST properly for the
31514          *  full ECMAScript range.
31515          *
31516          *  The following has useful discussion and links:
31517          *
31518          *    https://bugzilla.mozilla.org/show_bug.cgi?id=351066
31519          */
31520
31521         duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/);
31522         DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038);
31523
31524         d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
31525         DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0);  /* unsigned 31-bit range */
31526         t = (time_t) (d / 1000.0);
31527         DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t));
31528
31529         duk_memzero((void *) tms, sizeof(struct tm) * 2);
31530
31531 #if defined(DUK_USE_DATE_TZO_GMTIME_R)
31532         (void) gmtime_r(&t, &tms[0]);
31533         (void) localtime_r(&t, &tms[1]);
31534 #elif defined(DUK_USE_DATE_TZO_GMTIME_S)
31535         (void) gmtime_s(&t, &tms[0]);
31536         (void) localtime_s(&t, &tms[1]);
31537 #elif defined(DUK_USE_DATE_TZO_GMTIME)
31538         tm_ptr = gmtime(&t);
31539         duk_memcpy((void *) &tms[0], tm_ptr, sizeof(struct tm));
31540         tm_ptr = localtime(&t);
31541         duk_memcpy((void *) &tms[1], tm_ptr, sizeof(struct tm));
31542 #else
31543 #error internal error
31544 #endif
31545         DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
31546                              "wday:%ld,yday:%ld,isdst:%ld}",
31547                              (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour,
31548                              (long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year,
31549                              (long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst));
31550         DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
31551                              "wday:%ld,yday:%ld,isdst:%ld}",
31552                              (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour,
31553                              (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year,
31554                              (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst));
31555
31556         /* tm_isdst is both an input and an output to mktime(), use 0 to
31557          * avoid DST handling in mktime():
31558          * - https://github.com/svaarala/duktape/issues/406
31559          * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
31560          */
31561         tms[0].tm_isdst = 0;
31562         tms[1].tm_isdst = 0;
31563         t1 = mktime(&tms[0]);  /* UTC */
31564         t2 = mktime(&tms[1]);  /* local */
31565         if (t1 == (time_t) -1 || t2 == (time_t) -1) {
31566                 /* This check used to be for (t < 0) but on some platforms
31567                  * time_t is unsigned and apparently the proper way to detect
31568                  * an mktime() error return is the cast above.  See e.g.:
31569                  * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
31570                  */
31571                 goto mktime_error;
31572         }
31573         DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
31574
31575         /* Compute final offset in seconds, positive if local time ahead of
31576          * UTC (returned value is UTC-to-local offset).
31577          *
31578          * difftime() returns a double, so coercion to int generates quite
31579          * a lot of code.  Direct subtraction is not portable, however.
31580          * XXX: allow direct subtraction on known platforms.
31581          */
31582 #if 0
31583         return (duk_int_t) (t2 - t1);
31584 #endif
31585         return (duk_int_t) difftime(t2, t1);
31586
31587  mktime_error:
31588         /* XXX: return something more useful, so that caller can throw? */
31589         DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
31590         return 0;
31591 }
31592 #endif  /* DUK_USE_DATE_TZO_GMTIME */
31593
31594 #if defined(DUK_USE_DATE_PRS_STRPTIME)
31595 DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_hthread *thr, const char *str) {
31596         struct tm tm;
31597         time_t t;
31598         char buf[DUK__STRPTIME_BUF_SIZE];
31599
31600         /* Copy to buffer with slack to avoid Valgrind gripes from strptime. */
31601         DUK_ASSERT(str != NULL);
31602         duk_memzero(buf, sizeof(buf));  /* valgrind whine without this */
31603         DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
31604         buf[sizeof(buf) - 1] = (char) 0;
31605
31606         DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
31607
31608         duk_memzero(&tm, sizeof(tm));
31609         if (strptime((const char *) buf, "%c", &tm) != NULL) {
31610                 DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
31611                                      "wday:%ld,yday:%ld,isdst:%ld}",
31612                                      (long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour,
31613                                      (long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year,
31614                                      (long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst));
31615                 tm.tm_isdst = -1;  /* negative: dst info not available */
31616
31617                 t = mktime(&tm);
31618                 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
31619                 if (t >= 0) {
31620                         duk_push_number(thr, ((duk_double_t) t) * 1000.0);
31621                         return 1;
31622                 }
31623         }
31624
31625         return 0;
31626 }
31627 #endif  /* DUK_USE_DATE_PRS_STRPTIME */
31628
31629 #if defined(DUK_USE_DATE_PRS_GETDATE)
31630 DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_hthread *thr, const char *str) {
31631         struct tm tm;
31632         duk_small_int_t rc;
31633         time_t t;
31634
31635         /* For this to work, DATEMSK must be set, so this is not very
31636          * convenient for an embeddable interpreter.
31637          */
31638
31639         duk_memzero(&tm, sizeof(struct tm));
31640         rc = (duk_small_int_t) getdate_r(str, &tm);
31641         DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
31642
31643         if (rc == 0) {
31644                 t = mktime(&tm);
31645                 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
31646                 if (t >= 0) {
31647                         duk_push_number(thr, (duk_double_t) t);
31648                         return 1;
31649                 }
31650         }
31651
31652         return 0;
31653 }
31654 #endif  /* DUK_USE_DATE_PRS_GETDATE */
31655
31656 #if defined(DUK_USE_DATE_FMT_STRFTIME)
31657 DUK_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) {
31658         char buf[DUK__STRFTIME_BUF_SIZE];
31659         struct tm tm;
31660         const char *fmt;
31661
31662         DUK_UNREF(tzoffset);
31663
31664         /* If the platform doesn't support the entire ECMAScript range, we need
31665          * to return 0 so that the caller can fall back to the default formatter.
31666          *
31667          * For now, assume that if time_t is 8 bytes or more, the whole ECMAScript
31668          * range is supported.  For smaller time_t values (4 bytes in practice),
31669          * assumes that the signed 32-bit range is supported.
31670          *
31671          * XXX: detect this more correctly per platform.  The size of time_t is
31672          * probably not an accurate guarantee of strftime() supporting or not
31673          * supporting a large time range (the full ECMAScript range).
31674          */
31675         if (sizeof(time_t) < 8 &&
31676             (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
31677                 /* be paranoid for 32-bit time values (even avoiding negative ones) */
31678                 return 0;
31679         }
31680
31681         duk_memzero(&tm, sizeof(tm));
31682         tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
31683         tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
31684         tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
31685         tm.tm_mday = parts[DUK_DATE_IDX_DAY];       /* already one-based */
31686         tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1;  /* one-based -> zero-based */
31687         tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900;
31688         tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
31689         tm.tm_isdst = 0;
31690
31691         duk_memzero(buf, sizeof(buf));
31692         if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
31693                 fmt = "%c";
31694         } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
31695                 fmt = "%x";
31696         } else {
31697                 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
31698                 fmt = "%X";
31699         }
31700         (void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
31701         DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
31702
31703         duk_push_string(thr, buf);
31704         return 1;
31705 }
31706 #endif  /* DUK_USE_DATE_FMT_STRFTIME */
31707
31708 #if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
31709 DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) {
31710         struct timespec ts;
31711
31712         if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
31713                 return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0;
31714         } else {
31715                 DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed"));
31716                 return 0.0;
31717         }
31718 }
31719 #endif
31720
31721 /* automatic undefs */
31722 #undef DUK__STRFTIME_BUF_SIZE
31723 #undef DUK__STRPTIME_BUF_SIZE
31724 #line 1 "duk_bi_date_windows.c"
31725 /*
31726  *  Windows Date providers
31727  *
31728  *  Platform specific links:
31729  *
31730  *    - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
31731  */
31732
31733 /* #include duk_internal.h -> already included */
31734
31735 /* The necessary #includes are in place in duk_config.h. */
31736
31737 #if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
31738 /* Shared Windows helpers. */
31739 DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
31740         FILETIME ft;
31741         if (SystemTimeToFileTime(st, &ft) == 0) {
31742                 DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
31743                 res->QuadPart = 0;
31744         } else {
31745                 res->LowPart = ft.dwLowDateTime;
31746                 res->HighPart = ft.dwHighDateTime;
31747         }
31748 }
31749
31750 #if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
31751 DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) {
31752         res->LowPart = ft->dwLowDateTime;
31753         res->HighPart = ft->dwHighDateTime;
31754 }
31755 #endif  /* DUK_USE_DATE_NOW_WINDOWS_SUBMS */
31756
31757 DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
31758         duk_memzero((void *) st, sizeof(*st));
31759         st->wYear = 1970;
31760         st->wMonth = 1;
31761         st->wDayOfWeek = 4;  /* not sure whether or not needed; Thursday */
31762         st->wDay = 1;
31763         DUK_ASSERT(st->wHour == 0);
31764         DUK_ASSERT(st->wMinute == 0);
31765         DUK_ASSERT(st->wSecond == 0);
31766         DUK_ASSERT(st->wMilliseconds == 0);
31767 }
31768 #endif  /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
31769
31770 #if defined(DUK_USE_DATE_NOW_WINDOWS)
31771 DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) {
31772         /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
31773          * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
31774          */
31775         SYSTEMTIME st1, st2;
31776         ULARGE_INTEGER tmp1, tmp2;
31777
31778         GetSystemTime(&st1);
31779         duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
31780
31781         duk__set_systime_jan1970(&st2);
31782         duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
31783
31784         /* Difference is in 100ns units, convert to milliseconds, keeping
31785          * fractions since Duktape 2.2.0.  This is only theoretical because
31786          * SYSTEMTIME is limited to milliseconds.
31787          */
31788         return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
31789 }
31790 #endif  /* DUK_USE_DATE_NOW_WINDOWS */
31791
31792 #if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
31793 DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) {
31794         /* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime()
31795          * for more accuracy.
31796          */
31797         FILETIME ft1;
31798         SYSTEMTIME st2;
31799         ULARGE_INTEGER tmp1, tmp2;
31800
31801         GetSystemTimePreciseAsFileTime(&ft1);
31802         duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1);
31803
31804         duk__set_systime_jan1970(&st2);
31805         duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
31806
31807         /* Difference is in 100ns units, convert to milliseconds, keeping
31808          * fractions since Duktape 2.2.0.
31809          */
31810         return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
31811 }
31812 #endif  /* DUK_USE_DATE_NOW_WINDOWS */
31813
31814 #if defined(DUK_USE_DATE_TZO_WINDOWS)
31815 DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
31816         SYSTEMTIME st1;
31817         SYSTEMTIME st2;
31818         SYSTEMTIME st3;
31819         ULARGE_INTEGER tmp1;
31820         ULARGE_INTEGER tmp2;
31821         ULARGE_INTEGER tmp3;
31822         FILETIME ft1;
31823         BOOL ret;
31824
31825         /* XXX: handling of timestamps outside Windows supported range.
31826          * How does Windows deal with dates before 1600?  Does windows
31827          * support all ECMAScript years (like -200000 and +200000)?
31828          * Should equivalent year mapping be used here too?  If so, use
31829          * a shared helper (currently integrated into timeval-to-parts).
31830          */
31831
31832         /* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
31833          * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
31834          */
31835
31836         duk__set_systime_jan1970(&st1);
31837         duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
31838         tmp2.QuadPart = (ULONGLONG) (d * 10000.0);  /* millisec -> 100ns units since jan 1, 1970 */
31839         tmp2.QuadPart += tmp1.QuadPart;             /* input 'd' in Windows UTC, 100ns units */
31840
31841         ft1.dwLowDateTime = tmp2.LowPart;
31842         ft1.dwHighDateTime = tmp2.HighPart;
31843         ret = FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
31844         if (!ret) {
31845                 DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
31846                 return 0;
31847         }
31848         if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
31849                 DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
31850                 return 0;
31851         }
31852         duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
31853
31854         /* Positive if local time ahead of UTC. */
31855         return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000));  /* seconds */
31856 }
31857 #endif  /* DUK_USE_DATE_TZO_WINDOWS */
31858
31859 #if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
31860 DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
31861         SYSTEMTIME st1;
31862         SYSTEMTIME st2;
31863         FILETIME ft1;
31864         FILETIME ft2;
31865         ULARGE_INTEGER tmp1;
31866         ULARGE_INTEGER tmp2;
31867         BOOL ret;
31868
31869         /* Do a similar computation to duk_bi_date_get_local_tzoffset_windows
31870          * but without accounting for daylight savings time.  Use this on
31871          * Windows platforms (like Durango) that don't support the
31872          * SystemTimeToTzSpecificLocalTime() call.
31873          */
31874
31875         /* current time not needed for this computation */
31876         DUK_UNREF(d);
31877
31878         duk__set_systime_jan1970(&st1);
31879         duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
31880
31881         ft1.dwLowDateTime = tmp1.LowPart;
31882         ft1.dwHighDateTime = tmp1.HighPart;
31883         ret = FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2);
31884         if (!ret) {
31885                 DUK_D(DUK_DPRINT("FileTimeToLocalFileTime() failed, return tzoffset 0"));
31886                 return 0;
31887         }
31888
31889         ret = FileTimeToSystemTime((const FILETIME *) &ft2, &st2);
31890         if (!ret) {
31891                 DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
31892                 return 0;
31893         }
31894         duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
31895
31896         return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000));  /* seconds */
31897 }
31898 #endif  /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */
31899
31900 #if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
31901 DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) {
31902         LARGE_INTEGER count, freq;
31903
31904         /* There are legacy issues with QueryPerformanceCounter():
31905          * - Potential jumps: https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward
31906          * - Differences between cores (XP): https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
31907          *
31908          * We avoid these by enabling QPC by default only for Vista or later.
31909          */
31910
31911         if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) {
31912                 /* XXX: QueryPerformanceFrequency() can be cached */
31913                 return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0;
31914         } else {
31915                 /* MSDN: "On systems that run Windows XP or later, the function
31916                  * will always succeed and will thus never return zero."
31917                  * Provide minimal error path just in case user enables this
31918                  * feature in pre-XP Windows.
31919                  */
31920                 return 0.0;
31921         }
31922 }
31923 #endif  /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */
31924 #line 1 "duk_bi_duktape.c"
31925 /*
31926  *  Duktape built-ins
31927  *
31928  *  Size optimization note: it might seem that vararg multipurpose functions
31929  *  like fin(), enc(), and dec() are not very size optimal, but using a single
31930  *  user-visible ECMAScript function saves a lot of run-time footprint; each
31931  *  Function instance takes >100 bytes.  Using a shared native helper and a
31932  *  'magic' value won't save much if there are multiple Function instances
31933  *  anyway.
31934  */
31935
31936 /* #include duk_internal.h -> already included */
31937
31938 #if defined(DUK_USE_DUKTAPE_BUILTIN)
31939
31940 DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) {
31941         duk_inspect_value(thr, -1);
31942         return 1;
31943 }
31944
31945 DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) {
31946         duk_int_t level;
31947
31948         level = duk_to_int(thr, 0);
31949         duk_inspect_callstack_entry(thr, level);
31950         return 1;
31951 }
31952
31953 DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) {
31954         duk_small_uint_t flags;
31955
31956         flags = (duk_small_uint_t) duk_get_uint(thr, 0);
31957         duk_heap_mark_and_sweep(thr->heap, flags);
31958
31959         /* XXX: Not sure what the best return value would be in the API.
31960          * Return true for now.
31961          */
31962         duk_push_true(thr);
31963         return 1;
31964 }
31965
31966 #if defined(DUK_USE_FINALIZER_SUPPORT)
31967 DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_hthread *thr) {
31968         (void) duk_require_hobject(thr, 0);
31969         if (duk_get_top(thr) >= 2) {
31970                 /* Set: currently a finalizer is disabled by setting it to
31971                  * undefined; this does not remove the property at the moment.
31972                  * The value could be type checked to be either a function
31973                  * or something else; if something else, the property could
31974                  * be deleted.  Must use duk_set_finalizer() to keep
31975                  * DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync.
31976                  */
31977                 duk_set_top(thr, 2);
31978                 duk_set_finalizer(thr, 0);
31979                 return 0;
31980         } else {
31981                 /* Get. */
31982                 DUK_ASSERT(duk_get_top(thr) == 1);
31983                 duk_get_finalizer(thr, 0);
31984                 return 1;
31985         }
31986 }
31987 #endif  /* DUK_USE_FINALIZER_SUPPORT */
31988
31989 DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_hthread *thr) {
31990         duk_hstring *h_str;
31991
31992         /* Vararg function: must be careful to check/require arguments.
31993          * The JSON helpers accept invalid indices and treat them like
31994          * non-existent optional parameters.
31995          */
31996
31997         h_str = duk_require_hstring(thr, 0);  /* Could reject symbols, but no point: won't match comparisons. */
31998         duk_require_valid_index(thr, 1);
31999
32000         if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
32001                 duk_set_top(thr, 2);
32002                 duk_hex_encode(thr, 1);
32003                 DUK_ASSERT_TOP(thr, 2);
32004         } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
32005                 duk_set_top(thr, 2);
32006                 duk_base64_encode(thr, 1);
32007                 DUK_ASSERT_TOP(thr, 2);
32008 #if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
32009         } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
32010                 duk_bi_json_stringify_helper(thr,
32011                                              1 /*idx_value*/,
32012                                              2 /*idx_replacer*/,
32013                                              3 /*idx_space*/,
32014                                              DUK_JSON_FLAG_EXT_CUSTOM |
32015                                              DUK_JSON_FLAG_ASCII_ONLY |
32016                                              DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
32017 #endif
32018 #if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
32019         } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
32020                 duk_bi_json_stringify_helper(thr,
32021                                              1 /*idx_value*/,
32022                                              2 /*idx_replacer*/,
32023                                              3 /*idx_space*/,
32024                                              DUK_JSON_FLAG_EXT_COMPATIBLE |
32025                                              DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
32026 #endif
32027         } else {
32028                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
32029         }
32030         return 1;
32031 }
32032
32033 DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_hthread *thr) {
32034         duk_hstring *h_str;
32035
32036         /* Vararg function: must be careful to check/require arguments.
32037          * The JSON helpers accept invalid indices and treat them like
32038          * non-existent optional parameters.
32039          */
32040
32041         h_str = duk_require_hstring(thr, 0);  /* Could reject symbols, but no point: won't match comparisons */
32042         duk_require_valid_index(thr, 1);
32043
32044         if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
32045                 duk_set_top(thr, 2);
32046                 duk_hex_decode(thr, 1);
32047                 DUK_ASSERT_TOP(thr, 2);
32048         } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
32049                 duk_set_top(thr, 2);
32050                 duk_base64_decode(thr, 1);
32051                 DUK_ASSERT_TOP(thr, 2);
32052 #if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
32053         } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
32054                 duk_bi_json_parse_helper(thr,
32055                                          1 /*idx_value*/,
32056                                          2 /*idx_replacer*/,
32057                                          DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
32058 #endif
32059 #if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
32060         } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
32061                 duk_bi_json_parse_helper(thr,
32062                                          1 /*idx_value*/,
32063                                          2 /*idx_replacer*/,
32064                                          DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
32065 #endif
32066         } else {
32067                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
32068         }
32069         return 1;
32070 }
32071
32072 /*
32073  *  Compact an object
32074  */
32075
32076 DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_hthread *thr) {
32077         DUK_ASSERT_TOP(thr, 1);
32078         duk_compact(thr, 0);
32079         return 1;  /* return the argument object */
32080 }
32081
32082 #endif  /* DUK_USE_DUKTAPE_BUILTIN */
32083 #line 1 "duk_bi_encoding.c"
32084 /*
32085  *  WHATWG Encoding API built-ins
32086  *
32087  *  API specification: https://encoding.spec.whatwg.org/#api
32088  *  Web IDL: https://www.w3.org/TR/WebIDL/
32089  */
32090
32091 /* #include duk_internal.h -> already included */
32092
32093 /*
32094  *  Data structures for encoding/decoding
32095  */
32096
32097 typedef struct {
32098         duk_uint8_t *out;      /* where to write next byte(s) */
32099         duk_codepoint_t lead;  /* lead surrogate */
32100 } duk__encode_context;
32101
32102 typedef struct {
32103         /* UTF-8 decoding state */
32104         duk_codepoint_t codepoint;  /* built up incrementally */
32105         duk_uint8_t upper;          /* max value of next byte (decode error otherwise) */
32106         duk_uint8_t lower;          /* min value of next byte (ditto) */
32107         duk_uint8_t needed;         /* how many more bytes we need */
32108         duk_uint8_t bom_handled;    /* BOM seen or no longer expected */
32109
32110         /* Decoder configuration */
32111         duk_uint8_t fatal;
32112         duk_uint8_t ignore_bom;
32113 } duk__decode_context;
32114
32115 /* The signed duk_codepoint_t type is used to signal a decoded codepoint
32116  * (>= 0) or various other states using negative values.
32117  */
32118 #define DUK__CP_CONTINUE   (-1)  /* continue to next byte, no completed codepoint */
32119 #define DUK__CP_ERROR      (-2)  /* decoding error */
32120 #define DUK__CP_RETRY      (-3)  /* decoding error; retry last byte */
32121
32122 /*
32123  *  Raw helpers for encoding/decoding
32124  */
32125
32126 /* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */
32127 DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) {
32128         *ptr++ = 0xef;
32129         *ptr++ = 0xbf;
32130         *ptr++ = 0xbd;
32131         return ptr;
32132 }
32133
32134 DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) {
32135         /* (Re)init the decoding state of 'dec_ctx' but leave decoder
32136          * configuration fields untouched.
32137          */
32138         dec_ctx->codepoint = 0x0000L;
32139         dec_ctx->upper = 0xbf;
32140         dec_ctx->lower = 0x80;
32141         dec_ctx->needed = 0;
32142         dec_ctx->bom_handled = 0;
32143 }
32144
32145 DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) {
32146         /*
32147          *  UTF-8 algorithm based on the Encoding specification:
32148          *  https://encoding.spec.whatwg.org/#utf-8-decoder
32149          *
32150          *  Two main states: decoding initial byte vs. decoding continuation
32151          *  bytes.  Shortest length encoding is validated by restricting the
32152          *  allowed range of first continuation byte using 'lower' and 'upper'.
32153          */
32154
32155         if (dec_ctx->needed == 0) {
32156                 /* process initial byte */
32157                 if (x <= 0x7f) {
32158                         /* U+0000-U+007F, 1 byte (ASCII) */
32159                         return (duk_codepoint_t) x;
32160                 } else if (x >= 0xc2 && x <= 0xdf) {
32161                         /* U+0080-U+07FF, 2 bytes */
32162                         dec_ctx->needed = 1;
32163                         dec_ctx->codepoint = x & 0x1f;
32164                         DUK_ASSERT(dec_ctx->lower == 0x80);
32165                         DUK_ASSERT(dec_ctx->upper == 0xbf);
32166                         return DUK__CP_CONTINUE;
32167                 } else if (x >= 0xe0 && x <= 0xef) {
32168                         /* U+0800-U+FFFF, 3 bytes */
32169                         if (x == 0xe0) {
32170                                 dec_ctx->lower = 0xa0;
32171                                 DUK_ASSERT(dec_ctx->upper == 0xbf);
32172                         } else if (x == 0xed) {
32173                                 DUK_ASSERT(dec_ctx->lower == 0x80);
32174                                 dec_ctx->upper = 0x9f;
32175                         }
32176                         dec_ctx->needed = 2;
32177                         dec_ctx->codepoint = x & 0x0f;
32178                         return DUK__CP_CONTINUE;
32179                 } else if (x >= 0xf0 && x <= 0xf4) {
32180                         /* U+010000-U+10FFFF, 4 bytes */
32181                         if (x == 0xf0) {
32182                                 dec_ctx->lower = 0x90;
32183                                 DUK_ASSERT(dec_ctx->upper == 0xbf);
32184                         } else if (x == 0xf4) {
32185                                 DUK_ASSERT(dec_ctx->lower == 0x80);
32186                                 dec_ctx->upper = 0x8f;
32187                         }
32188                         dec_ctx->needed = 3;
32189                         dec_ctx->codepoint = x & 0x07;
32190                         return DUK__CP_CONTINUE;
32191                 } else {
32192                         /* not a legal initial byte */
32193                         return DUK__CP_ERROR;
32194                 }
32195         } else {
32196                 /* process continuation byte */
32197                 if (x >= dec_ctx->lower && x <= dec_ctx->upper) {
32198                         dec_ctx->lower = 0x80;
32199                         dec_ctx->upper = 0xbf;
32200                         dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f);
32201                         if (--dec_ctx->needed > 0) {
32202                                 /* need more bytes */
32203                                 return DUK__CP_CONTINUE;
32204                         } else {
32205                                 /* got a codepoint */
32206                                 duk_codepoint_t ret;
32207                                 DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL);  /* Decoding rules guarantee. */
32208                                 ret = dec_ctx->codepoint;
32209                                 dec_ctx->codepoint = 0x0000L;
32210                                 dec_ctx->needed = 0;
32211                                 return ret;
32212                         }
32213                 } else {
32214                         /* We just encountered an illegal UTF-8 continuation byte.  This might
32215                          * be the initial byte of the next character; if we return a plain
32216                          * error status and the decoder is in replacement mode, the character
32217                          * will be masked.  We still need to alert the caller to the error
32218                          * though.
32219                          */
32220                         dec_ctx->codepoint = 0x0000L;
32221                         dec_ctx->needed = 0;
32222                         dec_ctx->lower = 0x80;
32223                         dec_ctx->upper = 0xbf;
32224                         return DUK__CP_RETRY;
32225                 }
32226         }
32227 }
32228
32229 #if defined(DUK_USE_ENCODING_BUILTINS)
32230 DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) {
32231         duk__encode_context *enc_ctx;
32232
32233         DUK_ASSERT(codepoint >= 0);
32234         enc_ctx = (duk__encode_context *) udata;
32235         DUK_ASSERT(enc_ctx != NULL);
32236
32237 #if !defined(DUK_USE_PREFER_SIZE)
32238         if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) {
32239                 /* Fast path for ASCII. */
32240                 *enc_ctx->out++ = (duk_uint8_t) codepoint;
32241                 return;
32242         }
32243 #endif
32244
32245         if (DUK_UNLIKELY(codepoint > 0x10ffffL)) {
32246                 /* cannot legally encode in UTF-8 */
32247                 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
32248         } else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) {
32249                 if (codepoint <= 0xdbffL) {
32250                         /* high surrogate */
32251                         duk_codepoint_t prev_lead = enc_ctx->lead;
32252                         enc_ctx->lead = codepoint;
32253                         if (prev_lead == 0x0000L) {
32254                                 /* high surrogate, no output */
32255                                 return;
32256                         } else {
32257                                 /* consecutive high surrogates, consider first one unpaired */
32258                                 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
32259                         }
32260                 } else {
32261                         /* low surrogate */
32262                         if (enc_ctx->lead != 0x0000L) {
32263                                 codepoint = (duk_codepoint_t) (0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L));
32264                                 enc_ctx->lead = 0x0000L;
32265                         } else {
32266                                 /* unpaired low surrogate */
32267                                 DUK_ASSERT(enc_ctx->lead == 0x0000L);
32268                                 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
32269                         }
32270                 }
32271         } else {
32272                 if (enc_ctx->lead != 0x0000L) {
32273                         /* unpaired high surrogate: emit replacement character and the input codepoint */
32274                         enc_ctx->lead = 0x0000L;
32275                         enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out);
32276                 }
32277         }
32278
32279         /* Codepoint may be original input, a decoded surrogate pair, or may
32280          * have been replaced with U+FFFD.
32281          */
32282         enc_ctx->out += duk_unicode_encode_xutf8((duk_ucodepoint_t) codepoint, enc_ctx->out);
32283 }
32284 #endif  /* DUK_USE_ENCODING_BUILTINS */
32285
32286 /* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8
32287  * decoder.
32288  */
32289 DUK_LOCAL duk_ret_t duk__decode_helper(duk_hthread *thr, duk__decode_context *dec_ctx) {
32290         const duk_uint8_t *input;
32291         duk_size_t len = 0;
32292         duk_size_t len_tmp;
32293         duk_bool_t stream = 0;
32294         duk_codepoint_t codepoint;
32295         duk_uint8_t *output;
32296         const duk_uint8_t *in;
32297         duk_uint8_t *out;
32298
32299         DUK_ASSERT(dec_ctx != NULL);
32300
32301         /* Careful with input buffer pointer: any side effects involving
32302          * code execution (e.g. getters, coercion calls, and finalizers)
32303          * may cause a resize and invalidate a pointer we've read.  This
32304          * is why the pointer is actually looked up at the last minute.
32305          * Argument validation must still happen first to match WHATWG
32306          * required side effect order.
32307          */
32308
32309         if (duk_is_undefined(thr, 0)) {
32310                 duk_push_fixed_buffer_nozero(thr, 0);
32311                 duk_replace(thr, 0);
32312         }
32313         (void) duk_require_buffer_data(thr, 0, &len);  /* Need 'len', avoid pointer. */
32314
32315         if (duk_check_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
32316                                         DUK_TYPE_MASK_NULL |
32317                                         DUK_TYPE_MASK_NONE)) {
32318                 /* Use defaults, treat missing value like undefined. */
32319         } else {
32320                 duk_require_type_mask(thr, 1, DUK_TYPE_MASK_UNDEFINED |
32321                                               DUK_TYPE_MASK_NULL |
32322                                               DUK_TYPE_MASK_LIGHTFUNC |
32323                                               DUK_TYPE_MASK_BUFFER |
32324                                               DUK_TYPE_MASK_OBJECT);
32325                 if (duk_get_prop_literal(thr, 1, "stream")) {
32326                         stream = duk_to_boolean(thr, -1);
32327                 }
32328         }
32329
32330         /* Allowance is 3*len in the general case because all bytes may potentially
32331          * become U+FFFD.  If the first byte completes a non-BMP codepoint it will
32332          * decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to
32333          * compensate: (1*3)+3 = 6.  Non-BMP codepoints are safe otherwise because
32334          * the 4->6 expansion is well under the 3x allowance.
32335          *
32336          * XXX: As with TextEncoder, need a better buffer allocation strategy here.
32337          */
32338         if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) {
32339                 DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
32340                 DUK_WO_NORETURN(return 0;);
32341         }
32342         output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, 3 + (3 * len));  /* used parts will be always manually written over */
32343
32344         input = (const duk_uint8_t *) duk_get_buffer_data(thr, 0, &len_tmp);
32345         DUK_ASSERT(input != NULL || len == 0);
32346         if (DUK_UNLIKELY(len != len_tmp)) {
32347                 /* Very unlikely but possible: source buffer was resized by
32348                  * a side effect when fixed buffer was pushed.  Output buffer
32349                  * may not be large enough to hold output, so just fail if
32350                  * length has changed.
32351                  */
32352                 DUK_D(DUK_DPRINT("input buffer resized by side effect, fail"));
32353                 goto fail_type;
32354         }
32355
32356         /* From this point onwards it's critical that no side effect occur
32357          * which may disturb 'input': finalizer execution, property accesses,
32358          * active coercions, etc.  Even an allocation related mark-and-sweep
32359          * may affect the pointer because it may trigger a pending finalizer.
32360          */
32361
32362         in = input;
32363         out = output;
32364         while (in < input + len) {
32365                 codepoint = duk__utf8_decode_next(dec_ctx, *in++);
32366                 if (codepoint < 0) {
32367                         if (codepoint == DUK__CP_CONTINUE) {
32368                                 continue;
32369                         }
32370
32371                         /* Decoding error with or without retry. */
32372                         DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY);
32373                         if (codepoint == DUK__CP_RETRY) {
32374                                 --in;  /* retry last byte */
32375                         }
32376                         /* replacement mode: replace with U+FFFD */
32377                         codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
32378                         if (dec_ctx->fatal) {
32379                                 /* fatal mode: throw a TypeError */
32380                                 goto fail_type;
32381                         }
32382                         /* Continue with 'codepoint', Unicode replacement. */
32383                 }
32384                 DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL);
32385
32386                 if (!dec_ctx->bom_handled) {
32387                         dec_ctx->bom_handled = 1;
32388                         if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) {
32389                                 continue;
32390                         }
32391                 }
32392
32393                 out += duk_unicode_encode_cesu8((duk_ucodepoint_t) codepoint, out);
32394                 DUK_ASSERT(out <= output + (3 + (3 * len)));
32395         }
32396
32397         if (!stream) {
32398                 if (dec_ctx->needed != 0) {
32399                         /* truncated sequence at end of buffer */
32400                         if (dec_ctx->fatal) {
32401                                 goto fail_type;
32402                         } else {
32403                                 out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out);
32404                                 DUK_ASSERT(out <= output + (3 + (3 * len)));
32405                         }
32406                 }
32407                 duk__utf8_decode_init(dec_ctx);  /* Initialize decoding state for potential reuse. */
32408         }
32409
32410         /* Output buffer is fixed and thus stable even if there had been
32411          * side effects (which there shouldn't be).
32412          */
32413         duk_push_lstring(thr, (const char *) output, (duk_size_t) (out - output));
32414         return 1;
32415
32416  fail_type:
32417         DUK_ERROR_TYPE(thr, DUK_STR_UTF8_DECODE_FAILED);
32418         DUK_WO_NORETURN(return 0;);
32419 }
32420
32421 /*
32422  *  Built-in bindings
32423  */
32424
32425 #if defined(DUK_USE_ENCODING_BUILTINS)
32426 DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_hthread *thr) {
32427         /* TextEncoder currently requires no persistent state, so the constructor
32428          * does nothing on purpose.
32429          */
32430
32431         duk_require_constructor_call(thr);
32432         return 0;
32433 }
32434
32435 DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_hthread *thr) {
32436         duk_push_literal(thr, "utf-8");
32437         return 1;
32438 }
32439
32440 DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_hthread *thr) {
32441         duk__encode_context enc_ctx;
32442         duk_size_t len;
32443         duk_size_t final_len;
32444         duk_uint8_t *output;
32445
32446         DUK_ASSERT_TOP(thr, 1);
32447         if (duk_is_undefined(thr, 0)) {
32448                 len = 0;
32449         } else {
32450                 duk_hstring *h_input;
32451
32452                 h_input = duk_to_hstring(thr, 0);
32453                 DUK_ASSERT(h_input != NULL);
32454
32455                 len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input);
32456                 if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) {
32457                         DUK_ERROR_TYPE(thr, DUK_STR_RESULT_TOO_LONG);
32458                         DUK_WO_NORETURN(return 0;);
32459                 }
32460         }
32461
32462         /* Allowance is 3*len because all bytes can potentially be replaced with
32463          * U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8.
32464          * Rely on dynamic buffer data pointer stability: no other code has
32465          * access to the data pointer.
32466          *
32467          * XXX: The buffer allocation strategy used here is rather inefficient.
32468          * Maybe switch to a chunk-based strategy, or preprocess the string to
32469          * figure out the space needed ahead of time?
32470          */
32471         DUK_ASSERT(3 * len >= len);
32472         output = (duk_uint8_t *) duk_push_dynamic_buffer(thr, 3 * len);
32473
32474         if (len > 0) {
32475                 DUK_ASSERT(duk_is_string(thr, 0));  /* True if len > 0. */
32476
32477                 /* XXX: duk_decode_string() is used to process the input
32478                  * string.  For standard ECMAScript strings, represented
32479                  * internally as CESU-8, this is fine.  However, behavior
32480                  * beyond CESU-8 is not very strict: codepoints using an
32481                  * extended form of UTF-8 are also accepted, and invalid
32482                  * codepoint sequences (which are allowed in Duktape strings)
32483                  * are not handled as well as they could (e.g. invalid
32484                  * continuation bytes may mask following codepoints).
32485                  * This is how ECMAScript code would also see such strings.
32486                  * Maybe replace duk_decode_string() with an explicit strict
32487                  * CESU-8 decoder here?
32488                  */
32489                 enc_ctx.lead = 0x0000L;
32490                 enc_ctx.out = output;
32491                 duk_decode_string(thr, 0, duk__utf8_encode_char, (void *) &enc_ctx);
32492                 if (enc_ctx.lead != 0x0000L) {
32493                         /* unpaired high surrogate at end of string */
32494                         enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out);
32495                         DUK_ASSERT(enc_ctx.out <= output + (3 * len));
32496                 }
32497
32498                 /* The output buffer is usually very much oversized, so shrink it to
32499                  * actually needed size.  Pointer stability assumed up to this point.
32500                  */
32501                 DUK_ASSERT_TOP(thr, 2);
32502                 DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(thr, -1, NULL));
32503
32504                 final_len = (duk_size_t) (enc_ctx.out - output);
32505                 duk_resize_buffer(thr, -1, final_len);
32506                 /* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */
32507         } else {
32508                 final_len = 0;
32509         }
32510
32511         /* Standard WHATWG output is a Uint8Array.  Here the Uint8Array will
32512          * be backed by a dynamic buffer which differs from e.g. Uint8Arrays
32513          * created as 'new Uint8Array(N)'.  ECMAScript code won't see the
32514          * difference but C code will.  When bufferobjects are not supported,
32515          * returns a plain dynamic buffer.
32516          */
32517 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
32518         duk_push_buffer_object(thr, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY);
32519 #endif
32520         return 1;
32521 }
32522
32523 DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_hthread *thr) {
32524         duk__decode_context *dec_ctx;
32525         duk_bool_t fatal = 0;
32526         duk_bool_t ignore_bom = 0;
32527
32528         DUK_ASSERT_TOP(thr, 2);
32529         duk_require_constructor_call(thr);
32530         if (!duk_is_undefined(thr, 0)) {
32531                 /* XXX: For now ignore 'label' (encoding identifier). */
32532                 duk_to_string(thr, 0);
32533         }
32534         if (!duk_is_null_or_undefined(thr, 1)) {
32535                 if (duk_get_prop_literal(thr, 1, "fatal")) {
32536                         fatal = duk_to_boolean(thr, -1);
32537                 }
32538                 if (duk_get_prop_literal(thr, 1, "ignoreBOM")) {
32539                         ignore_bom = duk_to_boolean(thr, -1);
32540                 }
32541         }
32542
32543         duk_push_this(thr);
32544
32545         /* The decode context is not assumed to be zeroed; all fields are
32546          * initialized explicitly.
32547          */
32548         dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(thr, sizeof(duk__decode_context));
32549         dec_ctx->fatal = (duk_uint8_t) fatal;
32550         dec_ctx->ignore_bom = (duk_uint8_t) ignore_bom;
32551         duk__utf8_decode_init(dec_ctx);  /* Initializes remaining fields. */
32552
32553         duk_put_prop_literal(thr, -2, DUK_INTERNAL_SYMBOL("Context"));
32554         return 0;
32555 }
32556
32557 /* Get TextDecoder context from 'this'; leaves garbage on stack. */
32558 DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_hthread *thr) {
32559         duk__decode_context *dec_ctx;
32560         duk_push_this(thr);
32561         duk_get_prop_literal(thr, -1, DUK_INTERNAL_SYMBOL("Context"));
32562         dec_ctx = (duk__decode_context *) duk_require_buffer(thr, -1, NULL);
32563         DUK_ASSERT(dec_ctx != NULL);
32564         return dec_ctx;
32565 }
32566
32567 DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_hthread *thr) {
32568         duk__decode_context *dec_ctx;
32569         duk_int_t magic;
32570
32571         dec_ctx = duk__get_textdecoder_context(thr);
32572         magic = duk_get_current_magic(thr);
32573         switch (magic) {
32574         case 0:
32575                 /* Encoding is now fixed, so _Context lookup is only needed to
32576                  * validate the 'this' binding (TypeError if not TextDecoder-like).
32577                  */
32578                 duk_push_literal(thr, "utf-8");
32579                 break;
32580         case 1:
32581                 duk_push_boolean(thr, dec_ctx->fatal);
32582                 break;
32583         default:
32584                 duk_push_boolean(thr, dec_ctx->ignore_bom);
32585                 break;
32586         }
32587
32588         return 1;
32589 }
32590
32591 DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_hthread *thr) {
32592         duk__decode_context *dec_ctx;
32593
32594         dec_ctx = duk__get_textdecoder_context(thr);
32595         return duk__decode_helper(thr, dec_ctx);
32596 }
32597 #endif  /* DUK_USE_ENCODING_BUILTINS */
32598
32599 /*
32600  *  Internal helper for Node.js Buffer
32601  */
32602
32603 /* Internal helper used for Node.js Buffer .toString().  Value stack convention
32604  * is currently odd: it mimics TextDecoder .decode() so that argument must be at
32605  * index 0, and decode options (not present for Buffer) at index 1.  Return value
32606  * is a Duktape/C function return value.
32607  */
32608 DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_hthread *thr) {
32609         duk__decode_context dec_ctx;
32610
32611         dec_ctx.fatal = 0;  /* use replacement chars */
32612         dec_ctx.ignore_bom = 1;  /* ignore BOMs (matches Node.js Buffer .toString()) */
32613         duk__utf8_decode_init(&dec_ctx);
32614
32615         return duk__decode_helper(thr, &dec_ctx);
32616 }
32617
32618 /* automatic undefs */
32619 #undef DUK__CP_CONTINUE
32620 #undef DUK__CP_ERROR
32621 #undef DUK__CP_RETRY
32622 #line 1 "duk_bi_error.c"
32623 /*
32624  *  Error built-ins
32625  */
32626
32627 /* #include duk_internal.h -> already included */
32628
32629 DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_hthread *thr) {
32630         /* Behavior for constructor and non-constructor call is
32631          * the same except for augmenting the created error.  When
32632          * called as a constructor, the caller (duk_new()) will handle
32633          * augmentation; when called as normal function, we need to do
32634          * it here.
32635          */
32636
32637         duk_small_int_t bidx_prototype = duk_get_current_magic(thr);
32638
32639         /* same for both error and each subclass like TypeError */
32640         duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
32641                                      DUK_HOBJECT_FLAG_FASTREFS |
32642                                      DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
32643
32644         (void) duk_push_object_helper(thr, flags_and_class, bidx_prototype);
32645
32646         /* If message is undefined, the own property 'message' is not set at
32647          * all to save property space.  An empty message is inherited anyway.
32648          */
32649         if (!duk_is_undefined(thr, 0)) {
32650                 duk_to_string(thr, 0);
32651                 duk_dup_0(thr);  /* [ message error message ] */
32652                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
32653         }
32654
32655         /* Augment the error if called as a normal function.  __FILE__ and __LINE__
32656          * are not desirable in this case.
32657          */
32658
32659 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
32660         if (!duk_is_constructor_call(thr)) {
32661                 duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE);
32662         }
32663 #endif
32664
32665         return 1;
32666 }
32667
32668 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_hthread *thr) {
32669         /* XXX: optimize with more direct internal access */
32670
32671         duk_push_this(thr);
32672         (void) duk_require_hobject_promote_mask(thr, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
32673
32674         /* [ ... this ] */
32675
32676         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
32677         if (duk_is_undefined(thr, -1)) {
32678                 duk_pop(thr);
32679                 duk_push_literal(thr, "Error");
32680         } else {
32681                 duk_to_string(thr, -1);
32682         }
32683
32684         /* [ ... this name ] */
32685
32686         /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
32687          * accident or are they actually needed?  The first ToString()
32688          * could conceivably return 'undefined'.
32689          */
32690         duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
32691         if (duk_is_undefined(thr, -1)) {
32692                 duk_pop(thr);
32693                 duk_push_hstring_empty(thr);
32694         } else {
32695                 duk_to_string(thr, -1);
32696         }
32697
32698         /* [ ... this name message ] */
32699
32700         if (duk_get_length(thr, -2) == 0) {
32701                 /* name is empty -> return message */
32702                 return 1;
32703         }
32704         if (duk_get_length(thr, -1) == 0) {
32705                 /* message is empty -> return name */
32706                 duk_pop(thr);
32707                 return 1;
32708         }
32709         duk_push_literal(thr, ": ");
32710         duk_insert(thr, -2);  /* ... name ': ' message */
32711         duk_concat(thr, 3);
32712
32713         return 1;
32714 }
32715
32716 #if defined(DUK_USE_TRACEBACKS)
32717
32718 /*
32719  *  Traceback handling
32720  *
32721  *  The unified helper decodes the traceback and produces various requested
32722  *  outputs.  It should be optimized for size, and may leave garbage on stack,
32723  *  only the topmost return value matters.  For instance, traceback separator
32724  *  and decoded strings are pushed even when looking for filename only.
32725  *
32726  *  NOTE: although _Tracedata is an internal property, user code can currently
32727  *  write to the array (or replace it with something other than an array).
32728  *  The code below must tolerate arbitrary _Tracedata.  It can throw errors
32729  *  etc, but cannot cause a segfault or memory unsafe behavior.
32730  */
32731
32732 /* constants arbitrary, chosen for small loads */
32733 #define DUK__OUTPUT_TYPE_TRACEBACK   (-1)
32734 #define DUK__OUTPUT_TYPE_FILENAME    0
32735 #define DUK__OUTPUT_TYPE_LINENUMBER  1
32736
32737 DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_hthread *thr, duk_small_int_t output_type) {
32738         duk_idx_t idx_td;
32739         duk_small_int_t i;  /* traceback depth fits into 16 bits */
32740         duk_small_int_t t;  /* stack type fits into 16 bits */
32741         duk_small_int_t count_func = 0;  /* traceback depth ensures fits into 16 bits */
32742         const char *str_tailcall = " tailcall";
32743         const char *str_strict = " strict";
32744         const char *str_construct = " construct";
32745         const char *str_prevyield = " preventsyield";
32746         const char *str_directeval = " directeval";
32747         const char *str_empty = "";
32748
32749         DUK_ASSERT_TOP(thr, 0);  /* fixed arg count */
32750
32751         duk_push_this(thr);
32752         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TRACEDATA);
32753         idx_td = duk_get_top_index(thr);
32754
32755         duk_push_hstring_stridx(thr, DUK_STRIDX_NEWLINE_4SPACE);
32756         duk_push_this(thr);
32757
32758         /* [ ... this tracedata sep this ] */
32759
32760         /* XXX: skip null filename? */
32761
32762         if (duk_check_type(thr, idx_td, DUK_TYPE_OBJECT)) {
32763                 /* Current tracedata contains 2 entries per callstack entry. */
32764                 for (i = 0; ; i += 2) {
32765                         duk_int_t pc;
32766                         duk_uint_t line;
32767                         duk_uint_t flags;
32768                         duk_double_t d;
32769                         const char *funcname;
32770                         const char *filename;
32771                         duk_hobject *h_func;
32772                         duk_hstring *h_name;
32773
32774                         duk_require_stack(thr, 5);
32775                         duk_get_prop_index(thr, idx_td, (duk_uarridx_t) i);
32776                         duk_get_prop_index(thr, idx_td, (duk_uarridx_t) (i + 1));
32777                         d = duk_to_number_m1(thr);
32778                         pc = duk_double_to_int_t(DUK_FMOD(d, DUK_DOUBLE_2TO32));
32779                         flags = duk_double_to_uint_t(DUK_FLOOR(d / DUK_DOUBLE_2TO32));
32780                         t = (duk_small_int_t) duk_get_type(thr, -2);
32781
32782                         if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
32783                                 /*
32784                                  *  ECMAScript/native function call or lightfunc call
32785                                  */
32786
32787                                 count_func++;
32788
32789                                 /* [ ... v1(func) v2(pc+flags) ] */
32790
32791                                 /* These may be systematically omitted by Duktape
32792                                  * with certain config options, but allow user to
32793                                  * set them on a case-by-case basis.
32794                                  */
32795                                 duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
32796                                 duk_get_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME);
32797
32798 #if defined(DUK_USE_PC2LINE)
32799                                 line = (duk_uint_t) duk_hobject_pc2line_query(thr, -4, (duk_uint_fast32_t) pc);
32800 #else
32801                                 line = 0;
32802 #endif
32803
32804                                 /* [ ... v1 v2 name filename ] */
32805
32806                                 /* When looking for .fileName/.lineNumber, blame first
32807                                  * function which has a .fileName.
32808                                  */
32809                                 if (duk_is_string_notsymbol(thr, -1)) {
32810                                         if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
32811                                                 return 1;
32812                                         } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
32813                                                 duk_push_uint(thr, line);
32814                                                 return 1;
32815                                         }
32816                                 }
32817
32818                                 /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
32819                                 /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
32820                                 h_name = duk_get_hstring_notsymbol(thr, -2);  /* may be NULL */
32821                                 funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
32822                                            "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
32823                                 filename = duk_get_string_notsymbol(thr, -1);
32824                                 filename = filename ? filename : "";
32825                                 DUK_ASSERT(funcname != NULL);
32826                                 DUK_ASSERT(filename != NULL);
32827
32828                                 h_func = duk_get_hobject(thr, -4);  /* NULL for lightfunc */
32829
32830                                 if (h_func == NULL) {
32831                                         duk_push_sprintf(thr, "at %s light%s%s%s%s%s",
32832                                                          (const char *) funcname,
32833                                                          (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
32834                                                          (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
32835                                                          (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
32836                                                          (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
32837                                                          (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
32838                                 } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) {
32839                                         duk_push_sprintf(thr, "at %s (%s) native%s%s%s%s%s",
32840                                                          (const char *) funcname,
32841                                                          (const char *) filename,
32842                                                          (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
32843                                                          (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
32844                                                          (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
32845                                                          (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
32846                                                          (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
32847                                 } else {
32848                                         duk_push_sprintf(thr, "at %s (%s:%lu)%s%s%s%s%s",
32849                                                          (const char *) funcname,
32850                                                          (const char *) filename,
32851                                                          (unsigned long) line,
32852                                                          (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
32853                                                          (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
32854                                                          (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
32855                                                          (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
32856                                                          (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
32857                                 }
32858                                 duk_replace(thr, -5);   /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
32859                                 duk_pop_3(thr);         /* -> [ ... str ] */
32860                         } else if (t == DUK_TYPE_STRING) {
32861                                 const char *str_file;
32862
32863                                 /*
32864                                  *  __FILE__ / __LINE__ entry, here 'pc' is line number directly.
32865                                  *  Sometimes __FILE__ / __LINE__ is reported as the source for
32866                                  *  the error (fileName, lineNumber), sometimes not.
32867                                  */
32868
32869                                 /* [ ... v1(filename) v2(line+flags) ] */
32870
32871                                 /* When looking for .fileName/.lineNumber, blame compilation
32872                                  * or C call site unless flagged not to do so.
32873                                  */
32874                                 if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
32875                                         if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
32876                                                 duk_pop(thr);
32877                                                 return 1;
32878                                         } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
32879                                                 duk_push_int(thr, pc);
32880                                                 return 1;
32881                                         }
32882                                 }
32883
32884                                 /* Tracedata is trusted but avoid any risk of using a NULL
32885                                  * for %s format because it has undefined behavior.  Symbols
32886                                  * don't need to be explicitly rejected as they pose no memory
32887                                  * safety issues.
32888                                  */
32889                                 str_file = (const char *) duk_get_string(thr, -2);
32890                                 duk_push_sprintf(thr, "at [anon] (%s:%ld) internal",
32891                                                  (const char *) (str_file ? str_file : "null"), (long) pc);
32892                                 duk_replace(thr, -3);  /* [ ... v1 v2 str ] -> [ ... str v2 ] */
32893                                 duk_pop(thr);          /* -> [ ... str ] */
32894                         } else {
32895                                 /* unknown, ignore */
32896                                 duk_pop_2(thr);
32897                                 break;
32898                         }
32899                 }
32900
32901                 if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
32902                         /* Possibly truncated; there is no explicit truncation
32903                          * marker so this is the best we can do.
32904                          */
32905
32906                         duk_push_hstring_stridx(thr, DUK_STRIDX_BRACKETED_ELLIPSIS);
32907                 }
32908         }
32909
32910         /* [ ... this tracedata sep this str1 ... strN ] */
32911
32912         if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
32913                 return 0;
32914         } else {
32915                 /* The 'this' after 'sep' will get ToString() coerced by
32916                  * duk_join() automatically.  We don't want to do that
32917                  * coercion when providing .fileName or .lineNumber (GH-254).
32918                  */
32919                 duk_join(thr, duk_get_top(thr) - (idx_td + 2) /*count, not including sep*/);
32920                 return 1;
32921         }
32922 }
32923
32924 /* XXX: Output type could be encoded into native function 'magic' value to
32925  * save space.  For setters the stridx could be encoded into 'magic'.
32926  */
32927
32928 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
32929         return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_TRACEBACK);
32930 }
32931
32932 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
32933         return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_FILENAME);
32934 }
32935
32936 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
32937         return duk__error_getter_helper(thr, DUK__OUTPUT_TYPE_LINENUMBER);
32938 }
32939
32940 #else  /* DUK_USE_TRACEBACKS */
32941
32942 /*
32943  *  Traceback handling when tracebacks disabled.
32944  *
32945  *  The fileName / lineNumber stubs are now necessary because built-in
32946  *  data will include the accessor properties in Error.prototype.  If those
32947  *  are removed for builds without tracebacks, these can also be removed.
32948  *  'stack' should still be present and produce a ToString() equivalent:
32949  *  this is useful for user code which prints a stacktrace and expects to
32950  *  see something useful.  A normal stacktrace also begins with a ToString()
32951  *  of the error so this makes sense.
32952  */
32953
32954 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_hthread *thr) {
32955         /* XXX: remove this native function and map 'stack' accessor
32956          * to the toString() implementation directly.
32957          */
32958         return duk_bi_error_prototype_to_string(thr);
32959 }
32960
32961 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_hthread *thr) {
32962         DUK_UNREF(thr);
32963         return 0;
32964 }
32965
32966 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_hthread *thr) {
32967         DUK_UNREF(thr);
32968         return 0;
32969 }
32970
32971 #endif  /* DUK_USE_TRACEBACKS */
32972
32973 DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_hthread *thr, duk_small_uint_t stridx_key) {
32974         /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
32975          * user code called Object.defineProperty() to create an overriding
32976          * own property.  This allows user code to overwrite .fileName etc
32977          * intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
32978          * See https://github.com/svaarala/duktape/issues/387.
32979          */
32980
32981         DUK_ASSERT_TOP(thr, 1);  /* fixed arg count: value */
32982
32983         duk_push_this(thr);
32984         duk_push_hstring_stridx(thr, stridx_key);
32985         duk_dup_0(thr);
32986
32987         /* [ ... obj key value ] */
32988
32989         DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
32990                            duk_get_tval(thr, -3), duk_get_tval(thr, -2), duk_get_tval(thr, -1)));
32991
32992         duk_def_prop(thr, -3, DUK_DEFPROP_HAVE_VALUE |
32993                               DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
32994                               DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
32995                               DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
32996         return 0;
32997 }
32998
32999 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_hthread *thr) {
33000         return duk__error_setter_helper(thr, DUK_STRIDX_STACK);
33001 }
33002
33003 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_hthread *thr) {
33004         return duk__error_setter_helper(thr, DUK_STRIDX_FILE_NAME);
33005 }
33006
33007 DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_hthread *thr) {
33008         return duk__error_setter_helper(thr, DUK_STRIDX_LINE_NUMBER);
33009 }
33010
33011 /* automatic undefs */
33012 #undef DUK__OUTPUT_TYPE_FILENAME
33013 #undef DUK__OUTPUT_TYPE_LINENUMBER
33014 #undef DUK__OUTPUT_TYPE_TRACEBACK
33015 #line 1 "duk_bi_function.c"
33016 /*
33017  *  Function built-ins
33018  */
33019
33020 /* #include duk_internal.h -> already included */
33021
33022 /* Needed even when Function built-in is disabled. */
33023 DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_hthread *thr) {
33024         /* ignore arguments, return undefined (E5 Section 15.3.4) */
33025         DUK_UNREF(thr);
33026         return 0;
33027 }
33028
33029 #if defined(DUK_USE_FUNCTION_BUILTIN)
33030 DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_hthread *thr) {
33031         duk_hstring *h_sourcecode;
33032         duk_idx_t nargs;
33033         duk_idx_t i;
33034         duk_small_uint_t comp_flags;
33035         duk_hcompfunc *func;
33036         duk_hobject *outer_lex_env;
33037         duk_hobject *outer_var_env;
33038
33039         /* normal and constructor calls have identical semantics */
33040
33041         nargs = duk_get_top(thr);
33042         for (i = 0; i < nargs; i++) {
33043                 duk_to_string(thr, i);  /* Rejects Symbols during coercion. */
33044         }
33045
33046         if (nargs == 0) {
33047                 duk_push_hstring_empty(thr);
33048                 duk_push_hstring_empty(thr);
33049         } else if (nargs == 1) {
33050                 /* XXX: cover this with the generic >1 case? */
33051                 duk_push_hstring_empty(thr);
33052         } else {
33053                 duk_insert(thr, 0);   /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
33054                 duk_push_literal(thr, ",");
33055                 duk_insert(thr, 1);
33056                 duk_join(thr, nargs - 1);
33057         }
33058
33059         /* [ body formals ], formals is comma separated list that needs to be parsed */
33060
33061         DUK_ASSERT_TOP(thr, 2);
33062
33063         /* XXX: this placeholder is not always correct, but use for now.
33064          * It will fail in corner cases; see test-dev-func-cons-args.js.
33065          */
33066         duk_push_literal(thr, "function(");
33067         duk_dup_1(thr);
33068         duk_push_literal(thr, "){");
33069         duk_dup_0(thr);
33070         duk_push_literal(thr, "\n}");  /* Newline is important to handle trailing // comment. */
33071         duk_concat(thr, 5);
33072
33073         /* [ body formals source ] */
33074
33075         DUK_ASSERT_TOP(thr, 3);
33076
33077         /* strictness is not inherited, intentional */
33078         comp_flags = DUK_COMPILE_FUNCEXPR;
33079
33080         duk_push_hstring_stridx(thr, DUK_STRIDX_COMPILE);  /* XXX: copy from caller? */  /* XXX: ignored now */
33081         h_sourcecode = duk_require_hstring(thr, -2);  /* no symbol check needed; -2 is concat'd code */
33082         duk_js_compile(thr,
33083                        (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
33084                        (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
33085                        comp_flags);
33086
33087         /* Force .name to 'anonymous' (ES2015). */
33088         duk_push_literal(thr, "anonymous");
33089         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
33090
33091         func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
33092         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
33093         DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func));
33094
33095         /* [ body formals source template ] */
33096
33097         /* only outer_lex_env matters, as functions always get a new
33098          * variable declaration environment.
33099          */
33100
33101         outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
33102         outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
33103
33104         duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/);
33105
33106         /* [ body formals source template closure ] */
33107
33108         return 1;
33109 }
33110 #endif  /* DUK_USE_FUNCTION_BUILTIN */
33111
33112 #if defined(DUK_USE_FUNCTION_BUILTIN)
33113 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_hthread *thr) {
33114         duk_tval *tv;
33115
33116         /*
33117          *  E5 Section 15.3.4.2 places few requirements on the output of
33118          *  this function: the result is implementation dependent, must
33119          *  follow FunctionDeclaration syntax (in particular, must have a
33120          *  name even for anonymous functions or functions with empty name).
33121          *  The output does NOT need to compile into anything useful.
33122          *
33123          *  E6 Section 19.2.3.5 changes the requirements completely: the
33124          *  result must either eval() to a functionally equivalent object
33125          *  OR eval() to a SyntaxError.
33126          *
33127          *  We opt for the SyntaxError approach for now, with a syntax that
33128          *  mimics V8's native function syntax:
33129          *
33130          *      'function cos() { [native code] }'
33131          *
33132          *  but extended with [ecmascript code], [bound code], and
33133          *  [lightfunc code].
33134          */
33135
33136         duk_push_this(thr);
33137         tv = DUK_GET_TVAL_NEGIDX(thr, -1);
33138         DUK_ASSERT(tv != NULL);
33139
33140         if (DUK_TVAL_IS_OBJECT(tv)) {
33141                 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
33142                 const char *func_name;
33143
33144                 /* Function name: missing/undefined is mapped to empty string,
33145                  * otherwise coerce to string.  No handling for invalid identifier
33146                  * characters or e.g. '{' in the function name.  This doesn't
33147                  * really matter as long as a SyntaxError results.  Technically
33148                  * if the name contained a suitable prefix followed by '//' it
33149                  * might cause the result to parse without error.
33150                  */
33151                 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME);
33152                 if (duk_is_undefined(thr, -1)) {
33153                         func_name = "";
33154                 } else {
33155                         func_name = duk_to_string(thr, -1);
33156                         DUK_ASSERT(func_name != NULL);
33157                 }
33158
33159                 if (DUK_HOBJECT_IS_COMPFUNC(obj)) {
33160                         duk_push_sprintf(thr, "function %s() { [ecmascript code] }", (const char *) func_name);
33161                 } else if (DUK_HOBJECT_IS_NATFUNC(obj)) {
33162                         duk_push_sprintf(thr, "function %s() { [native code] }", (const char *) func_name);
33163                 } else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) {
33164                         duk_push_sprintf(thr, "function %s() { [bound code] }", (const char *) func_name);
33165                 } else {
33166                         goto type_error;
33167                 }
33168         } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
33169                 duk_push_lightfunc_tostring(thr, tv);
33170         } else {
33171                 goto type_error;
33172         }
33173
33174         return 1;
33175
33176  type_error:
33177         DUK_DCERROR_TYPE_INVALID_ARGS(thr);
33178 }
33179 #endif
33180
33181 /* Always present because the native function pointer is needed in call
33182  * handling.
33183  */
33184 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_hthread *thr) {
33185         /* .call() is dealt with in call handling by simulating its
33186          * effects so this function is actually never called.
33187          */
33188         DUK_UNREF(thr);
33189         return DUK_RET_TYPE_ERROR;
33190 }
33191
33192 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_hthread *thr) {
33193         /* Like .call(), never actually called. */
33194         DUK_UNREF(thr);
33195         return DUK_RET_TYPE_ERROR;
33196 }
33197
33198 DUK_INTERNAL duk_ret_t duk_bi_reflect_apply(duk_hthread *thr) {
33199         /* Like .call(), never actually called. */
33200         DUK_UNREF(thr);
33201         return DUK_RET_TYPE_ERROR;
33202 }
33203
33204 DUK_INTERNAL duk_ret_t duk_bi_reflect_construct(duk_hthread *thr) {
33205         /* Like .call(), never actually called. */
33206         DUK_UNREF(thr);
33207         return DUK_RET_TYPE_ERROR;
33208 }
33209
33210 #if defined(DUK_USE_FUNCTION_BUILTIN)
33211 /* Create a bound function which points to a target function which may
33212  * be bound or non-bound.  If the target is bound, the argument lists
33213  * and 'this' binding of the functions are merged and the resulting
33214  * function points directly to the non-bound target.
33215  */
33216 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_hthread *thr) {
33217         duk_hboundfunc *h_bound;
33218         duk_idx_t nargs;  /* bound args, not counting 'this' binding */
33219         duk_idx_t bound_nargs;
33220         duk_int_t bound_len;
33221         duk_tval *tv_prevbound;
33222         duk_idx_t n_prevbound;
33223         duk_tval *tv_res;
33224         duk_tval *tv_tmp;
33225
33226         /* XXX: C API call, e.g. duk_push_bound_function(thr, target_idx, nargs); */
33227
33228         /* Vararg function, careful arg handling, e.g. thisArg may not
33229          * be present.
33230          */
33231         nargs = duk_get_top(thr) - 1;  /* actual args, not counting 'this' binding */
33232         if (nargs < 0) {
33233                 nargs++;
33234                 duk_push_undefined(thr);
33235         }
33236         DUK_ASSERT(nargs >= 0);
33237
33238         /* Limit 'nargs' for bound functions to guarantee arithmetic
33239          * below will never wrap.
33240          */
33241         if (nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
33242                 DUK_DCERROR_RANGE_INVALID_COUNT(thr);
33243         }
33244
33245         duk_push_this(thr);
33246         duk_require_callable(thr, -1);
33247
33248         /* [ thisArg arg1 ... argN func ]  (thisArg+args == nargs+1 total) */
33249         DUK_ASSERT_TOP(thr, nargs + 2);
33250
33251         /* Create bound function object. */
33252         h_bound = duk_push_hboundfunc(thr);
33253         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->target));
33254         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&h_bound->this_binding));
33255         DUK_ASSERT(h_bound->args == NULL);
33256         DUK_ASSERT(h_bound->nargs == 0);
33257         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_bound) == NULL);
33258
33259         /* [ thisArg arg1 ... argN func boundFunc ] */
33260
33261         /* If the target is a bound function, argument lists must be
33262          * merged.  The 'this' binding closest to the target function
33263          * wins because in call handling the 'this' gets replaced over
33264          * and over again until we call the non-bound function.
33265          */
33266         tv_prevbound = NULL;
33267         n_prevbound = 0;
33268         tv_tmp = DUK_GET_TVAL_POSIDX(thr, 0);
33269         DUK_TVAL_SET_TVAL(&h_bound->this_binding, tv_tmp);
33270         tv_tmp = DUK_GET_TVAL_NEGIDX(thr, -2);
33271         DUK_TVAL_SET_TVAL(&h_bound->target, tv_tmp);
33272
33273         if (DUK_TVAL_IS_OBJECT(tv_tmp)) {
33274                 duk_hobject *h_target;
33275                 duk_hobject *bound_proto;
33276
33277                 h_target = DUK_TVAL_GET_OBJECT(tv_tmp);
33278                 DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(h_target));
33279
33280                 /* Internal prototype must be copied from the target.
33281                  * For lightfuncs Function.prototype is used and is already
33282                  * in place.
33283                  */
33284                 bound_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target);
33285                 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
33286
33287                 /* The 'strict' flag is copied to get the special [[Get]] of E5.1
33288                  * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
33289                  * function.  Not sure if this is correct, because the specification
33290                  * is a bit ambiguous on this point but it would make sense.
33291                  */
33292                 /* Strictness is inherited from target. */
33293                 if (DUK_HOBJECT_HAS_STRICT(h_target)) {
33294                         DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
33295                 }
33296
33297                 if (DUK_HOBJECT_HAS_BOUNDFUNC(h_target)) {
33298                         duk_hboundfunc *h_boundtarget;
33299
33300                         h_boundtarget = (duk_hboundfunc *) (void *) h_target;
33301
33302                         /* The final function should always be non-bound, unless
33303                          * there's a bug in the internals.  Assert for it.
33304                          */
33305                         DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(&h_boundtarget->target) ||
33306                                    (DUK_TVAL_IS_OBJECT(&h_boundtarget->target) &&
33307                                     DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(&h_boundtarget->target)) &&
33308                                     !DUK_HOBJECT_IS_BOUNDFUNC(DUK_TVAL_GET_OBJECT(&h_boundtarget->target))));
33309
33310                         DUK_TVAL_SET_TVAL(&h_bound->target, &h_boundtarget->target);
33311                         DUK_TVAL_SET_TVAL(&h_bound->this_binding, &h_boundtarget->this_binding);
33312
33313                         tv_prevbound = h_boundtarget->args;
33314                         n_prevbound = h_boundtarget->nargs;
33315                 }
33316         } else {
33317                 /* Lightfuncs are always strict. */
33318                 duk_hobject *bound_proto;
33319
33320                 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
33321                 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_bound);
33322                 bound_proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
33323                 DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) h_bound, bound_proto);
33324         }
33325
33326         DUK_TVAL_INCREF(thr, &h_bound->target);  /* old values undefined, no decref needed */
33327         DUK_TVAL_INCREF(thr, &h_bound->this_binding);
33328
33329         bound_nargs = n_prevbound + nargs;
33330         if (bound_nargs > (duk_idx_t) DUK_HBOUNDFUNC_MAX_ARGS) {
33331                 DUK_DCERROR_RANGE_INVALID_COUNT(thr);
33332         }
33333         tv_res = (duk_tval *) DUK_ALLOC_CHECKED(thr, ((duk_size_t) bound_nargs) * sizeof(duk_tval));
33334         DUK_ASSERT(tv_res != NULL || bound_nargs == 0);
33335         DUK_ASSERT(h_bound->args == NULL);
33336         DUK_ASSERT(h_bound->nargs == 0);
33337         h_bound->args = tv_res;
33338         h_bound->nargs = bound_nargs;
33339
33340         DUK_ASSERT(n_prevbound >= 0);
33341         duk_copy_tvals_incref(thr, tv_res, tv_prevbound, (duk_size_t) n_prevbound);
33342         DUK_ASSERT(nargs >= 0);
33343         duk_copy_tvals_incref(thr, tv_res + n_prevbound, DUK_GET_TVAL_POSIDX(thr, 1), (duk_size_t) nargs);
33344
33345         /* [ thisArg arg1 ... argN func boundFunc ] */
33346
33347         /* Bound function 'length' property is interesting.
33348          * For lightfuncs, simply read the virtual property.
33349          */
33350         duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH);
33351         bound_len = duk_get_int(thr, -1);  /* ES2015: no coercion */
33352         if (bound_len < nargs) {
33353                 bound_len = 0;
33354         } else {
33355                 bound_len -= nargs;
33356         }
33357         if (sizeof(duk_int_t) > 4 && bound_len > (duk_int_t) DUK_UINT32_MAX) {
33358                 bound_len = (duk_int_t) DUK_UINT32_MAX;
33359         }
33360         duk_pop(thr);
33361         DUK_ASSERT(bound_len >= 0);
33362         tv_tmp = thr->valstack_top++;
33363         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv_tmp));
33364         DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv_tmp));
33365         DUK_TVAL_SET_U32(tv_tmp, (duk_uint32_t) bound_len);  /* in-place update, fastint */
33366         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);  /* attrs in E6 Section 9.2.4 */
33367
33368         /* XXX: could these be virtual? */
33369         /* Caller and arguments must use the same thrower, [[ThrowTypeError]]. */
33370         duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_CALLER);
33371         duk_xdef_prop_stridx_thrower(thr, -1, DUK_STRIDX_LC_ARGUMENTS);
33372
33373         /* Function name and fileName (non-standard). */
33374         duk_push_literal(thr, "bound ");  /* ES2015 19.2.3.2. */
33375         duk_get_prop_stridx(thr, -3, DUK_STRIDX_NAME);
33376         if (!duk_is_string_notsymbol(thr, -1)) {
33377                 /* ES2015 has requirement to check that .name of target is a string
33378                  * (also must check for Symbol); if not, targetName should be the
33379                  * empty string.  ES2015 19.2.3.2.
33380                  */
33381                 duk_pop(thr);
33382                 duk_push_hstring_empty(thr);
33383         }
33384         duk_concat(thr, 2);
33385         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
33386 #if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
33387         duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME);
33388         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
33389 #endif
33390
33391         DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
33392
33393         return 1;
33394 }
33395 #endif  /* DUK_USE_FUNCTION_BUILTIN */
33396
33397 /* %NativeFunctionPrototype% .length getter. */
33398 DUK_INTERNAL duk_ret_t duk_bi_native_function_length(duk_hthread *thr) {
33399         duk_tval *tv;
33400         duk_hnatfunc *h;
33401         duk_int16_t func_nargs;
33402
33403         tv = duk_get_borrowed_this_tval(thr);
33404         DUK_ASSERT(tv != NULL);
33405
33406         if (DUK_TVAL_IS_OBJECT(tv)) {
33407                 h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
33408                 DUK_ASSERT(h != NULL);
33409                 if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
33410                         goto fail_type;
33411                 }
33412                 func_nargs = h->nargs;
33413                 duk_push_int(thr, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs);
33414         } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
33415                 duk_small_uint_t lf_flags;
33416                 duk_small_uint_t lf_len;
33417
33418                 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
33419                 lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
33420                 duk_push_uint(thr, lf_len);
33421         } else {
33422                 goto fail_type;
33423         }
33424         return 1;
33425
33426  fail_type:
33427         DUK_DCERROR_TYPE_INVALID_ARGS(thr);
33428 }
33429
33430 /* %NativeFunctionPrototype% .name getter. */
33431 DUK_INTERNAL duk_ret_t duk_bi_native_function_name(duk_hthread *thr) {
33432         duk_tval *tv;
33433         duk_hnatfunc *h;
33434
33435         tv = duk_get_borrowed_this_tval(thr);
33436         DUK_ASSERT(tv != NULL);
33437
33438         if (DUK_TVAL_IS_OBJECT(tv)) {
33439                 h = (duk_hnatfunc *) DUK_TVAL_GET_OBJECT(tv);
33440                 DUK_ASSERT(h != NULL);
33441                 if (!DUK_HOBJECT_IS_NATFUNC((duk_hobject *) h)) {
33442                         goto fail_type;
33443                 }
33444 #if 0
33445                 duk_push_hnatfunc_name(thr, h);
33446 #endif
33447                 duk_push_hstring_empty(thr);
33448         } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
33449                 duk_push_lightfunc_name(thr, tv);
33450         } else {
33451                 goto fail_type;
33452         }
33453         return 1;
33454
33455  fail_type:
33456         DUK_DCERROR_TYPE_INVALID_ARGS(thr);
33457 }
33458
33459 #if defined(DUK_USE_SYMBOL_BUILTIN)
33460 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_hasinstance(duk_hthread *thr) {
33461         /* This binding: RHS, stack index 0: LHS. */
33462         duk_bool_t ret;
33463
33464         ret = duk_js_instanceof_ordinary(thr, DUK_GET_TVAL_POSIDX(thr, 0), DUK_GET_THIS_TVAL_PTR(thr));
33465         duk_push_boolean(thr, ret);
33466         return 1;
33467 }
33468 #endif  /* DUK_USE_SYMBOL_BUILTIN */
33469 #line 1 "duk_bi_global.c"
33470 /*
33471  *  Global object built-ins
33472  */
33473
33474 /* #include duk_internal.h -> already included */
33475
33476 /*
33477  *  Encoding/decoding helpers
33478  */
33479
33480 /* XXX: Could add fast path (for each transform callback) with direct byte
33481  * lookups (no shifting) and no explicit check for x < 0x80 before table
33482  * lookup.
33483  */
33484
33485 /* Macros for creating and checking bitmasks for character encoding.
33486  * Bit number is a bit counterintuitive, but minimizes code size.
33487  */
33488 #define DUK__MKBITS(a,b,c,d,e,f,g,h)  ((duk_uint8_t) ( \
33489         ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
33490         ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \
33491         ))
33492 #define DUK__CHECK_BITMASK(table,cp)  ((table)[(cp) >> 3] & (1 << ((cp) & 0x07)))
33493
33494 /* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
33495 DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = {
33496         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
33497         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
33498         DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x20-0x2f */
33499         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1),  /* 0x30-0x3f */
33500         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x40-0x4f */
33501         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1),  /* 0x50-0x5f */
33502         DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x60-0x6f */
33503         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0),  /* 0x70-0x7f */
33504 };
33505
33506 /* E5.1 Section 15.1.3.4: uriUnescaped */
33507 DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = {
33508         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
33509         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
33510         DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0),  /* 0x20-0x2f */
33511         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0),  /* 0x30-0x3f */
33512         DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x40-0x4f */
33513         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1),  /* 0x50-0x5f */
33514         DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x60-0x6f */
33515         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0),  /* 0x70-0x7f */
33516 };
33517
33518 /* E5.1 Section 15.1.3.1: uriReserved + '#' */
33519 DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = {
33520         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
33521         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
33522         DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1),  /* 0x20-0x2f */
33523         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1),  /* 0x30-0x3f */
33524         DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x40-0x4f */
33525         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x50-0x5f */
33526         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x60-0x6f */
33527         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x70-0x7f */
33528 };
33529
33530 /* E5.1 Section 15.1.3.2: empty */
33531 DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
33532         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
33533         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
33534         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x20-0x2f */
33535         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x30-0x3f */
33536         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x40-0x4f */
33537         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x50-0x5f */
33538         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x60-0x6f */
33539         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x70-0x7f */
33540 };
33541
33542 #if defined(DUK_USE_SECTION_B)
33543 /* E5.1 Section B.2.2, step 7. */
33544 DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
33545         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x00-0x0f */
33546         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0),  /* 0x10-0x1f */
33547         DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1),  /* 0x20-0x2f */
33548         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0),  /* 0x30-0x3f */
33549         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x40-0x4f */
33550         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1),  /* 0x50-0x5f */
33551         DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1),  /* 0x60-0x6f */
33552         DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0)   /* 0x70-0x7f */
33553 };
33554 #endif  /* DUK_USE_SECTION_B */
33555
33556 typedef struct {
33557         duk_hthread *thr;
33558         duk_hstring *h_str;
33559         duk_bufwriter_ctx bw;
33560         const duk_uint8_t *p;
33561         const duk_uint8_t *p_start;
33562         const duk_uint8_t *p_end;
33563 } duk__transform_context;
33564
33565 typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp);
33566
33567 /* XXX: refactor and share with other code */
33568 DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) {
33569         duk_small_int_t ch;
33570         duk_small_int_t t = 0;
33571
33572         while (n > 0) {
33573                 t = t * 16;
33574                 ch = (duk_small_int_t) duk_hex_dectab[*p++];
33575                 if (DUK_LIKELY(ch >= 0)) {
33576                         t += ch;
33577                 } else {
33578                         return -1;
33579                 }
33580                 n--;
33581         }
33582         return t;
33583 }
33584
33585 DUK_LOCAL int duk__transform_helper(duk_hthread *thr, duk__transform_callback callback, const void *udata) {
33586         duk__transform_context tfm_ctx_alloc;
33587         duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
33588         duk_codepoint_t cp;
33589
33590         tfm_ctx->thr = thr;
33591
33592         tfm_ctx->h_str = duk_to_hstring(thr, 0);
33593         DUK_ASSERT(tfm_ctx->h_str != NULL);
33594
33595         DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str));  /* initial size guess */
33596
33597         tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str);
33598         tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str);
33599         tfm_ctx->p = tfm_ctx->p_start;
33600
33601         while (tfm_ctx->p < tfm_ctx->p_end) {
33602                 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end);
33603                 callback(tfm_ctx, udata, cp);
33604         }
33605
33606         DUK_BW_COMPACT(thr, &tfm_ctx->bw);
33607
33608         (void) duk_buffer_to_string(thr, -1);  /* Safe if transform is safe. */
33609         return 1;
33610 }
33611
33612 DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
33613         duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
33614         duk_small_int_t len;
33615         duk_codepoint_t cp1, cp2;
33616         duk_small_int_t i, t;
33617         const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata;
33618
33619         /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
33620          * Codepoint range is restricted so this is a slightly too large
33621          * but doesn't matter.
33622          */
33623         DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH);
33624
33625         if (cp < 0) {
33626                 goto uri_error;
33627         } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) {
33628                 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
33629                 return;
33630         } else if (cp >= 0xdc00L && cp <= 0xdfffL) {
33631                 goto uri_error;
33632         } else if (cp >= 0xd800L && cp <= 0xdbffL) {
33633                 /* Needs lookahead */
33634                 if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) {
33635                         goto uri_error;
33636                 }
33637                 if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) {
33638                         goto uri_error;
33639                 }
33640                 cp1 = cp;
33641                 cp = (duk_codepoint_t) (((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L);
33642         } else if (cp > 0x10ffffL) {
33643                 /* Although we can allow non-BMP characters (they'll decode
33644                  * back into surrogate pairs), we don't allow extended UTF-8
33645                  * characters; they would encode to URIs which won't decode
33646                  * back because of strict UTF-8 checks in URI decoding.
33647                  * (However, we could just as well allow them here.)
33648                  */
33649                 goto uri_error;
33650         } else {
33651                 /* Non-BMP characters within valid UTF-8 range: encode as is.
33652                  * They'll decode back into surrogate pairs if the escaped
33653                  * output is decoded.
33654                  */
33655                 ;
33656         }
33657
33658         len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
33659         for (i = 0; i < len; i++) {
33660                 t = (duk_small_int_t) xutf8_buf[i];
33661                 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
33662                                       &tfm_ctx->bw,
33663                                       DUK_ASC_PERCENT,
33664                                       (duk_uint8_t) duk_uc_nybbles[t >> 4],
33665                                       (duk_uint8_t) duk_uc_nybbles[t & 0x0f]);
33666         }
33667
33668         return;
33669
33670  uri_error:
33671         DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
33672         DUK_WO_NORETURN(return;);
33673 }
33674
33675 DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
33676         const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata;
33677         duk_small_uint_t utf8_blen;
33678         duk_codepoint_t min_cp;
33679         duk_small_int_t t;  /* must be signed */
33680         duk_small_uint_t i;
33681
33682         /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH,
33683          * percent escape path writes max two times CESU-8 encoded BMP length.
33684          */
33685         DUK_BW_ENSURE(tfm_ctx->thr,
33686                       &tfm_ctx->bw,
33687                       (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ?
33688                       DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH));
33689
33690         if (cp == (duk_codepoint_t) '%') {
33691                 const duk_uint8_t *p = tfm_ctx->p;
33692                 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p);  /* bytes left */
33693
33694                 DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left));
33695
33696                 if (left < 2) {
33697                         goto uri_error;
33698                 }
33699
33700                 t = duk__decode_hex_escape(p, 2);
33701                 DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t));
33702                 if (t < 0) {
33703                         goto uri_error;
33704                 }
33705
33706                 if (t < 0x80) {
33707                         if (DUK__CHECK_BITMASK(reserved_table, t)) {
33708                                 /* decode '%xx' to '%xx' if decoded char in reserved set */
33709                                 DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start);
33710                                 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
33711                                                       &tfm_ctx->bw,
33712                                                       DUK_ASC_PERCENT,
33713                                                       p[0],
33714                                                       p[1]);
33715                         } else {
33716                                 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t);
33717                         }
33718                         tfm_ctx->p += 2;
33719                         return;
33720                 }
33721
33722                 /* Decode UTF-8 codepoint from a sequence of hex escapes.  The
33723                  * first byte of the sequence has been decoded to 't'.
33724                  *
33725                  * Note that UTF-8 validation must be strict according to the
33726                  * specification: E5.1 Section 15.1.3, decode algorithm step
33727                  * 4.d.vii.8.  URIError from non-shortest encodings is also
33728                  * specifically noted in the spec.
33729                  */
33730
33731                 DUK_ASSERT(t >= 0x80);
33732                 if (t < 0xc0) {
33733                         /* continuation byte */
33734                         goto uri_error;
33735                 } else if (t < 0xe0) {
33736                         /* 110x xxxx; 2 bytes */
33737                         utf8_blen = 2;
33738                         min_cp = 0x80L;
33739                         cp = t & 0x1f;
33740                 } else if (t < 0xf0) {
33741                         /* 1110 xxxx; 3 bytes */
33742                         utf8_blen = 3;
33743                         min_cp = 0x800L;
33744                         cp = t & 0x0f;
33745                 } else if (t < 0xf8) {
33746                         /* 1111 0xxx; 4 bytes */
33747                         utf8_blen = 4;
33748                         min_cp = 0x10000L;
33749                         cp = t & 0x07;
33750                 } else {
33751                         /* extended utf-8 not allowed for URIs */
33752                         goto uri_error;
33753                 }
33754
33755                 if (left < utf8_blen * 3 - 1) {
33756                         /* '%xx%xx...%xx', p points to char after first '%' */
33757                         goto uri_error;
33758                 }
33759
33760                 p += 3;
33761                 for (i = 1; i < utf8_blen; i++) {
33762                         /* p points to digit part ('%xy', p points to 'x') */
33763                         t = duk__decode_hex_escape(p, 2);
33764                         DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx",
33765                                              (long) i, (long) utf8_blen, (long) cp, (unsigned long) t));
33766                         if (t < 0) {
33767                                 goto uri_error;
33768                         }
33769                         if ((t & 0xc0) != 0x80) {
33770                                 goto uri_error;
33771                         }
33772                         cp = (cp << 6) + (t & 0x3f);
33773                         p += 3;
33774                 }
33775                 p--;  /* p overshoots */
33776                 tfm_ctx->p = p;
33777
33778                 DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp, (long) min_cp));
33779
33780                 if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) {
33781                         goto uri_error;
33782                 }
33783
33784                 /* The E5.1 algorithm checks whether or not a decoded codepoint
33785                  * is below 0x80 and perhaps may be in the "reserved" set.
33786                  * This seems pointless because the single byte UTF-8 case is
33787                  * handled separately, and non-shortest encodings are rejected.
33788                  * So, 'cp' cannot be below 0x80 here, and thus cannot be in
33789                  * the reserved set.
33790                  */
33791
33792                 /* utf-8 validation ensures these */
33793                 DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL);
33794
33795                 if (cp >= 0x10000L) {
33796                         cp -= 0x10000L;
33797                         DUK_ASSERT(cp < 0x100000L);
33798
33799                         DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
33800                         DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffL) + 0xdc00L));
33801                 } else {
33802                         DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
33803                 }
33804         } else {
33805                 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
33806         }
33807         return;
33808
33809  uri_error:
33810         DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
33811         DUK_WO_NORETURN(return;);
33812 }
33813
33814 #if defined(DUK_USE_SECTION_B)
33815 DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
33816         DUK_UNREF(udata);
33817
33818         DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6);
33819
33820         if (cp < 0) {
33821                 goto esc_error;
33822         } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) {
33823                 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
33824         } else if (cp < 0x100L) {
33825                 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
33826                                       &tfm_ctx->bw,
33827                                       (duk_uint8_t) DUK_ASC_PERCENT,
33828                                       (duk_uint8_t) duk_uc_nybbles[cp >> 4],
33829                                       (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
33830         } else if (cp < 0x10000L) {
33831                 DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr,
33832                                       &tfm_ctx->bw,
33833                                       (duk_uint8_t) DUK_ASC_PERCENT,
33834                                       (duk_uint8_t) DUK_ASC_LC_U,
33835                                       (duk_uint8_t) duk_uc_nybbles[cp >> 12],
33836                                       (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f],
33837                                       (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f],
33838                                       (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
33839         } else {
33840                 /* Characters outside BMP cannot be escape()'d.  We could
33841                  * encode them as surrogate pairs (for codepoints inside
33842                  * valid UTF-8 range, but not extended UTF-8).  Because
33843                  * escape() and unescape() are legacy functions, we don't.
33844                  */
33845                 goto esc_error;
33846         }
33847
33848         return;
33849
33850  esc_error:
33851         DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
33852         DUK_WO_NORETURN(return;);
33853 }
33854
33855 DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
33856         duk_small_int_t t;
33857
33858         DUK_UNREF(udata);
33859
33860         if (cp == (duk_codepoint_t) '%') {
33861                 const duk_uint8_t *p = tfm_ctx->p;
33862                 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p);  /* bytes left */
33863
33864                 if (left >= 5 && p[0] == 'u' &&
33865                     ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) {
33866                         cp = (duk_codepoint_t) t;
33867                         tfm_ctx->p += 5;
33868                 } else if (left >= 2 &&
33869                            ((t = duk__decode_hex_escape(p, 2)) >= 0)) {
33870                         cp = (duk_codepoint_t) t;
33871                         tfm_ctx->p += 2;
33872                 }
33873         }
33874
33875         DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
33876 }
33877 #endif  /* DUK_USE_SECTION_B */
33878
33879 /*
33880  *  Eval
33881  *
33882  *  Eval needs to handle both a "direct eval" and an "indirect eval".
33883  *  Direct eval handling needs access to the caller's activation so that its
33884  *  lexical environment can be accessed.  A direct eval is only possible from
33885  *  ECMAScript code; an indirect eval call is possible also from C code.
33886  *  When an indirect eval call is made from C code, there may not be a
33887  *  calling activation at all which needs careful handling.
33888  */
33889
33890 DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_hthread *thr) {
33891         duk_hstring *h;
33892         duk_activation *act_caller;
33893         duk_activation *act_eval;
33894         duk_hcompfunc *func;
33895         duk_hobject *outer_lex_env;
33896         duk_hobject *outer_var_env;
33897         duk_bool_t this_to_global = 1;
33898         duk_small_uint_t comp_flags;
33899         duk_int_t level = -2;
33900         duk_small_uint_t call_flags;
33901
33902         DUK_ASSERT(duk_get_top(thr) == 1 || duk_get_top(thr) == 2);  /* 2 when called by debugger */
33903         DUK_ASSERT(thr->callstack_top >= 1);  /* at least this function exists */
33904         DUK_ASSERT(thr->callstack_curr != NULL);
33905         DUK_ASSERT((thr->callstack_curr->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
33906                    (thr->callstack_top >= 2));  /* if direct eval, calling activation must exist */
33907
33908         /*
33909          *  callstack_top - 1 --> this function
33910          *  callstack_top - 2 --> caller (may not exist)
33911          *
33912          *  If called directly from C, callstack_top might be 1.  If calling
33913          *  activation doesn't exist, call must be indirect.
33914          */
33915
33916         h = duk_get_hstring_notsymbol(thr, 0);
33917         if (!h) {
33918                 /* Symbol must be returned as is, like any non-string values. */
33919                 return 1;  /* return arg as-is */
33920         }
33921
33922 #if defined(DUK_USE_DEBUGGER_SUPPORT)
33923         /* NOTE: level is used only by the debugger and should never be present
33924          * for an ECMAScript eval().
33925          */
33926         DUK_ASSERT(level == -2);  /* by default, use caller's environment */
33927         if (duk_get_top(thr) >= 2 && duk_is_number(thr, 1)) {
33928                 level = duk_get_int(thr, 1);
33929         }
33930         DUK_ASSERT(level <= -2);  /* This is guaranteed by debugger code. */
33931 #endif
33932
33933         /* [ source ] */
33934
33935         comp_flags = DUK_COMPILE_EVAL;
33936         act_eval = thr->callstack_curr;  /* this function */
33937         DUK_ASSERT(act_eval != NULL);
33938         act_caller = duk_hthread_get_activation_for_level(thr, level);
33939         if (act_caller != NULL) {
33940                 /* Have a calling activation, check for direct eval (otherwise
33941                  * assume indirect eval.
33942                  */
33943                 if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
33944                     (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
33945                         /* Only direct eval inherits strictness from calling code
33946                          * (E5.1 Section 10.1.1).
33947                          */
33948                         comp_flags |= DUK_COMPILE_STRICT;
33949                 }
33950         } else {
33951                 DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
33952         }
33953
33954         duk_push_hstring_stridx(thr, DUK_STRIDX_INPUT);  /* XXX: copy from caller? */
33955         duk_js_compile(thr,
33956                        (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
33957                        (duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
33958                        comp_flags);
33959         func = (duk_hcompfunc *) duk_known_hobject(thr, -1);
33960         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
33961
33962         /* [ source template ] */
33963
33964         /* E5 Section 10.4.2 */
33965
33966         if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
33967                 DUK_ASSERT(thr->callstack_top >= 2);
33968                 DUK_ASSERT(act_caller != NULL);
33969                 if (act_caller->lex_env == NULL) {
33970                         DUK_ASSERT(act_caller->var_env == NULL);
33971                         DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
33972
33973                         /* this may have side effects, so re-lookup act */
33974                         duk_js_init_activation_environment_records_delayed(thr, act_caller);
33975                 }
33976                 DUK_ASSERT(act_caller->lex_env != NULL);
33977                 DUK_ASSERT(act_caller->var_env != NULL);
33978
33979                 this_to_global = 0;
33980
33981                 if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
33982                         duk_hdecenv *new_env;
33983                         duk_hobject *act_lex_env;
33984
33985                         DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
33986                                              "var_env and lex_env to a fresh env, "
33987                                              "this_binding to caller's this_binding"));
33988
33989                         act_lex_env = act_caller->lex_env;
33990
33991                         new_env = duk_hdecenv_alloc(thr,
33992                                                     DUK_HOBJECT_FLAG_EXTENSIBLE |
33993                                                     DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
33994                         DUK_ASSERT(new_env != NULL);
33995                         duk_push_hobject(thr, (duk_hobject *) new_env);
33996
33997                         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
33998                         DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act_lex_env);
33999                         DUK_HOBJECT_INCREF_ALLOWNULL(thr, act_lex_env);
34000                         DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
34001
34002                         outer_lex_env = (duk_hobject *) new_env;
34003                         outer_var_env = (duk_hobject *) new_env;
34004
34005                         duk_insert(thr, 0);  /* stash to bottom of value stack to keep new_env reachable for duration of eval */
34006
34007                         /* compiler's responsibility */
34008                         DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
34009                 } else {
34010                         DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> "
34011                                              "var_env and lex_env to caller's envs, "
34012                                              "this_binding to caller's this_binding"));
34013
34014                         outer_lex_env = act_caller->lex_env;
34015                         outer_var_env = act_caller->var_env;
34016
34017                         /* compiler's responsibility */
34018                         DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
34019                 }
34020         } else {
34021                 DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
34022                                      "global object, this_binding to global object"));
34023
34024                 this_to_global = 1;
34025                 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
34026                 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
34027         }
34028
34029         /* Eval code doesn't need an automatic .prototype object. */
34030         duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
34031
34032         /* [ env? source template closure ] */
34033
34034         if (this_to_global) {
34035                 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
34036                 duk_push_hobject_bidx(thr, DUK_BIDX_GLOBAL);
34037         } else {
34038                 duk_tval *tv;
34039                 DUK_ASSERT(thr->callstack_top >= 2);
34040                 DUK_ASSERT(act_caller != NULL);
34041                 tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act_caller->bottom_byteoff - sizeof(duk_tval));  /* this is just beneath bottom */
34042                 DUK_ASSERT(tv >= thr->valstack);
34043                 duk_push_tval(thr, tv);
34044         }
34045
34046         DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
34047                              (duk_heaphdr *) outer_lex_env,
34048                              (duk_heaphdr *) outer_var_env,
34049                              duk_get_tval(thr, -1)));
34050
34051         /* [ env? source template closure this ] */
34052
34053         call_flags = 0;
34054         if (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
34055                 /* Set DIRECT_EVAL flag for the call; it's not strictly
34056                  * needed for the 'inner' eval call (the eval body) but
34057                  * current new.target implementation expects to find it
34058                  * so it can traverse direct eval chains up to the real
34059                  * calling function.
34060                  */
34061                 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
34062         }
34063         duk_handle_call_unprotected_nargs(thr, 0, call_flags);
34064
34065         /* [ env? source template result ] */
34066
34067         return 1;
34068 }
34069
34070 /*
34071  *  Parsing of ints and floats
34072  */
34073
34074 #if defined(DUK_USE_GLOBAL_BUILTIN)
34075 DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_hthread *thr) {
34076         duk_int32_t radix;
34077         duk_small_uint_t s2n_flags;
34078
34079         DUK_ASSERT_TOP(thr, 2);
34080         duk_to_string(thr, 0);  /* Reject symbols. */
34081
34082         radix = duk_to_int32(thr, 1);
34083
34084         /* While parseInt() recognizes 0xdeadbeef, it doesn't recognize
34085          * ES2015 0o123 or 0b10001.
34086          */
34087         s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
34088                     DUK_S2N_FLAG_ALLOW_GARBAGE |
34089                     DUK_S2N_FLAG_ALLOW_PLUS |
34090                     DUK_S2N_FLAG_ALLOW_MINUS |
34091                     DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
34092                     DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
34093
34094         /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT.
34095          *
34096          * Don't autodetect octals (from leading zeroes), require user code to
34097          * provide an explicit radix 8 for parsing octal.  See write-up from Mozilla:
34098          * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation
34099          */
34100
34101         if (radix != 0) {
34102                 if (radix < 2 || radix > 36) {
34103                         goto ret_nan;
34104                 }
34105                 if (radix != 16) {
34106                         s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
34107                 }
34108         } else {
34109                 radix = 10;
34110         }
34111
34112         duk_dup_0(thr);
34113         duk_numconv_parse(thr, (duk_small_int_t) radix, s2n_flags);
34114         return 1;
34115
34116  ret_nan:
34117         duk_push_nan(thr);
34118         return 1;
34119 }
34120 #endif  /* DUK_USE_GLOBAL_BUILTIN */
34121
34122 #if defined(DUK_USE_GLOBAL_BUILTIN)
34123 DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_hthread *thr) {
34124         duk_small_uint_t s2n_flags;
34125
34126         DUK_ASSERT_TOP(thr, 1);
34127         duk_to_string(thr, 0);  /* Reject symbols. */
34128
34129         /* XXX: check flags */
34130         s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
34131                     DUK_S2N_FLAG_ALLOW_EXP |
34132                     DUK_S2N_FLAG_ALLOW_GARBAGE |
34133                     DUK_S2N_FLAG_ALLOW_PLUS |
34134                     DUK_S2N_FLAG_ALLOW_MINUS |
34135                     DUK_S2N_FLAG_ALLOW_INF |
34136                     DUK_S2N_FLAG_ALLOW_FRAC |
34137                     DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
34138                     DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
34139                     DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
34140
34141         duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
34142         return 1;
34143 }
34144 #endif  /* DUK_USE_GLOBAL_BUILTIN */
34145
34146 /*
34147  *  Number checkers
34148  */
34149
34150 #if defined(DUK_USE_GLOBAL_BUILTIN)
34151 DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_hthread *thr) {
34152         duk_double_t d = duk_to_number(thr, 0);
34153         duk_push_boolean(thr, (duk_bool_t) DUK_ISNAN(d));
34154         return 1;
34155 }
34156 #endif  /* DUK_USE_GLOBAL_BUILTIN */
34157
34158 #if defined(DUK_USE_GLOBAL_BUILTIN)
34159 DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_hthread *thr) {
34160         duk_double_t d = duk_to_number(thr, 0);
34161         duk_push_boolean(thr, (duk_bool_t) DUK_ISFINITE(d));
34162         return 1;
34163 }
34164 #endif  /* DUK_USE_GLOBAL_BUILTIN */
34165
34166 /*
34167  *  URI handling
34168  */
34169
34170 #if defined(DUK_USE_GLOBAL_BUILTIN)
34171 DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_hthread *thr) {
34172         return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
34173 }
34174
34175 DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_hthread *thr) {
34176         return duk__transform_helper(thr, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
34177 }
34178
34179 DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_hthread *thr) {
34180         return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
34181 }
34182
34183 DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_hthread *thr) {
34184         return duk__transform_helper(thr, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
34185 }
34186
34187 #if defined(DUK_USE_SECTION_B)
34188 DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_hthread *thr) {
34189         return duk__transform_helper(thr, duk__transform_callback_escape, (const void *) NULL);
34190 }
34191
34192 DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_hthread *thr) {
34193         return duk__transform_helper(thr, duk__transform_callback_unescape, (const void *) NULL);
34194 }
34195 #endif  /* DUK_USE_SECTION_B */
34196 #endif  /* DUK_USE_GLOBAL_BUILTIN */
34197
34198 /* automatic undefs */
34199 #undef DUK__CHECK_BITMASK
34200 #undef DUK__MKBITS
34201 #line 1 "duk_bi_json.c"
34202 /*
34203  *  JSON built-ins.
34204  *
34205  *  See doc/json.rst.
34206  *
34207  *  Codepoints are handled as duk_uint_fast32_t to ensure that the full
34208  *  unsigned 32-bit range is supported.  This matters to e.g. JX.
34209  *
34210  *  Input parsing doesn't do an explicit end-of-input check at all.  This is
34211  *  safe: input string data is always NUL-terminated (0x00) and valid JSON
34212  *  inputs never contain plain NUL characters, so that as long as syntax checks
34213  *  are correct, we'll never read past the NUL.  This approach reduces code size
34214  *  and improves parsing performance, but it's critical that syntax checks are
34215  *  indeed correct!
34216  */
34217
34218 /* #include duk_internal.h -> already included */
34219
34220 #if defined(DUK_USE_JSON_SUPPORT)
34221
34222 /*
34223  *  Local defines and forward declarations.
34224  */
34225
34226 #define DUK__JSON_DECSTR_BUFSIZE 128
34227 #define DUK__JSON_DECSTR_CHUNKSIZE 64
34228 #define DUK__JSON_ENCSTR_CHUNKSIZE 64
34229 #define DUK__JSON_STRINGIFY_BUFSIZE 128
34230 #define DUK__JSON_MAX_ESC_LEN 10  /* '\Udeadbeef' */
34231
34232 DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
34233 DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
34234 #if defined(DUK_USE_JX)
34235 DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx);
34236 #endif
34237 DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx);
34238 DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
34239 DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
34240 DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
34241 DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx);
34242 #if defined(DUK_USE_JX)
34243 DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
34244 DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
34245 DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
34246 #endif
34247 DUK_LOCAL_DECL void duk__dec_number(duk_json_dec_ctx *js_ctx);
34248 DUK_LOCAL_DECL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx);
34249 DUK_LOCAL_DECL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx);
34250 DUK_LOCAL_DECL void duk__dec_object(duk_json_dec_ctx *js_ctx);
34251 DUK_LOCAL_DECL void duk__dec_array(duk_json_dec_ctx *js_ctx);
34252 DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx);
34253 DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx);
34254
34255 DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch);
34256 DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2);
34257 DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx);
34258 DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h);
34259 #if defined(DUK_USE_FASTINT)
34260 DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p);
34261 #endif
34262 DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx);
34263 DUK_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);
34264 DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k);
34265 DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
34266 DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
34267 DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
34268 DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx);
34269 DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx);
34270 DUK_LOCAL_DECL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
34271 DUK_LOCAL_DECL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv);
34272 DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx);
34273 #if defined(DUK_USE_FASTINT)
34274 DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
34275 #endif
34276 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
34277 DUK_LOCAL_DECL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
34278 DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
34279 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
34280 DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj);
34281 #endif
34282 #endif
34283 #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
34284 DUK_LOCAL_DECL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
34285 #endif
34286 DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth);
34287
34288 /*
34289  *  Helper tables
34290  */
34291
34292 #if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
34293 DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = {
34294         /* 0x00 ... 0x7f: as is
34295          * 0x80: escape generically
34296          * 0x81: slow path
34297          * 0xa0 ... 0xff: backslash + one char
34298          */
34299
34300         0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80,
34301         0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
34302         0x20, 0x21, 0xa2, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
34303         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
34304         0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
34305         0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0xdc, 0x5d, 0x5e, 0x5f,
34306         0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
34307         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x81,
34308         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
34309         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
34310         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
34311         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
34312         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
34313         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
34314         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
34315         0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81
34316 };
34317 #else  /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
34318 DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = {
34319         DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
34320         DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
34321         DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL,
34322         DUK_ASC_LC_F, DUK_ASC_LC_R
34323 };
34324 #endif  /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
34325
34326 #if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
34327 DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = {
34328         /* 0x00: slow path
34329          * other: as is
34330          */
34331         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34332         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34333         0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
34334         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
34335         0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
34336         0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x00, 0x5d, 0x5e, 0x5f,
34337         0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
34338         0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
34339         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
34340         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
34341         0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
34342         0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
34343         0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
34344         0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
34345         0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
34346         0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
34347 };
34348 #endif  /* DUK_USE_JSON_DECSTRING_FASTPATH */
34349
34350 #if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
34351 DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = {
34352         /* 0x00: finish (non-white)
34353          * 0x01: continue
34354          */
34355         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
34356         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34357         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34358         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34359         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34360         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34361         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34362         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34363         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34364         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34365         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34366         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34367         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34368         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34369         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34370         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
34371 };
34372 #endif  /* DUK_USE_JSON_EATWHITE_FASTPATH */
34373
34374 #if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
34375 DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = {
34376         /* 0x00: finish (not part of number)
34377          * 0x01: continue
34378          */
34379         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34380         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34381         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00,
34382         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34383         0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34384         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34385         0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34386         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34387         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34388         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34389         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34390         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34391         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34392         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34393         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34394         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
34395 };
34396 #endif  /* DUK_USE_JSON_DECNUMBER_FASTPATH */
34397
34398 /*
34399  *  Parsing implementation.
34400  *
34401  *  JSON lexer is now separate from duk_lexer.c because there are numerous
34402  *  small differences making it difficult to share the lexer.
34403  *
34404  *  The parser here works with raw bytes directly; this works because all
34405  *  JSON delimiters are ASCII characters.  Invalid xUTF-8 encoded values
34406  *  inside strings will be passed on without normalization; this is not a
34407  *  compliance concern because compliant inputs will always be valid
34408  *  CESU-8 encodings.
34409  */
34410
34411 DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) {
34412         /* Shared handler to minimize parser size.  Cause will be
34413          * hidden, unfortunately, but we'll have an offset which
34414          * is often quite enough.
34415          */
34416         DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON,
34417                        (long) (js_ctx->p - js_ctx->p_start));
34418         DUK_WO_NORETURN(return;);
34419 }
34420
34421 DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
34422         const duk_uint8_t *p;
34423         duk_uint8_t t;
34424
34425         p = js_ctx->p;
34426         for (;;) {
34427                 DUK_ASSERT(p <= js_ctx->p_end);
34428                 t = *p;
34429
34430 #if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
34431                 /* This fast path is pretty marginal in practice.
34432                  * XXX: candidate for removal.
34433                  */
34434                 DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00);  /* end-of-input breaks */
34435                 if (duk__json_eatwhite_lookup[t] == 0) {
34436                         break;
34437                 }
34438 #else  /* DUK_USE_JSON_EATWHITE_FASTPATH */
34439                 if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) {
34440                         /* NUL also comes here.  Comparison order matters, 0x20
34441                          * is most common whitespace.
34442                          */
34443                         break;
34444                 }
34445 #endif  /* DUK_USE_JSON_EATWHITE_FASTPATH */
34446                 p++;
34447         }
34448         js_ctx->p = p;
34449 }
34450
34451 #if defined(DUK_USE_JX)
34452 DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) {
34453         DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
34454         return *js_ctx->p;
34455 }
34456 #endif
34457
34458 DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) {
34459         DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
34460         return *js_ctx->p++;
34461 }
34462
34463 DUK_LOCAL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
34464         duk__dec_eat_white(js_ctx);
34465         return duk__dec_get(js_ctx);
34466 }
34467
34468 /* For JX, expressing the whole unsigned 32-bit range matters. */
34469 DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) {
34470         duk_small_uint_t i;
34471         duk_uint_fast32_t res = 0;
34472         duk_uint8_t x;
34473         duk_small_int_t t;
34474
34475         for (i = 0; i < n; i++) {
34476                 /* XXX: share helper from lexer; duk_lexer.c / hexval(). */
34477
34478                 x = duk__dec_get(js_ctx);
34479                 DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld",
34480                                      (long) i, (long) n, (long) res, (long) x));
34481
34482                 /* x == 0x00 (EOF) causes syntax_error */
34483                 DUK_ASSERT(duk_hex_dectab[0] == -1);
34484                 t = duk_hex_dectab[x & 0xff];
34485                 if (DUK_LIKELY(t >= 0)) {
34486                         res = (res * 16) + (duk_uint_fast32_t) t;
34487                 } else {
34488                         /* catches EOF and invalid digits */
34489                         goto syntax_error;
34490                 }
34491         }
34492
34493         DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld", (long) res));
34494         return res;
34495
34496  syntax_error:
34497         duk__dec_syntax_error(js_ctx);
34498         DUK_UNREACHABLE();
34499         return 0;
34500 }
34501
34502 DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
34503         duk_hstring *h;
34504         const duk_uint8_t *p;
34505         duk_uint8_t x, y;
34506
34507         /* First character has already been eaten and checked by the caller.
34508          * We can scan until a NUL in stridx string because no built-in strings
34509          * have internal NULs.
34510          */
34511
34512         DUK_ASSERT_STRIDX_VALID(stridx);
34513         h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
34514         DUK_ASSERT(h != NULL);
34515
34516         p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1;
34517         DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1));  /* first character has been matched */
34518
34519         for (;;) {
34520                 x = *p;
34521                 if (x == 0) {
34522                         break;
34523                 }
34524                 y = duk__dec_get(js_ctx);
34525                 if (x != y) {
34526                         /* Catches EOF of JSON input. */
34527                         goto syntax_error;
34528                 }
34529                 p++;
34530         }
34531
34532         return;
34533
34534  syntax_error:
34535         duk__dec_syntax_error(js_ctx);
34536         DUK_UNREACHABLE();
34537 }
34538
34539 DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) {
34540         duk_uint_fast32_t cp;
34541
34542         /* EOF (-1) will be cast to an unsigned value first
34543          * and then re-cast for the switch.  In any case, it
34544          * will match the default case (syntax error).
34545          */
34546         cp = (duk_uint_fast32_t) duk__dec_get(js_ctx);
34547         switch (cp) {
34548         case DUK_ASC_BACKSLASH: break;
34549         case DUK_ASC_DOUBLEQUOTE: break;
34550         case DUK_ASC_SLASH: break;
34551         case DUK_ASC_LC_T: cp = 0x09; break;
34552         case DUK_ASC_LC_N: cp = 0x0a; break;
34553         case DUK_ASC_LC_R: cp = 0x0d; break;
34554         case DUK_ASC_LC_F: cp = 0x0c; break;
34555         case DUK_ASC_LC_B: cp = 0x08; break;
34556         case DUK_ASC_LC_U: {
34557                 cp = duk__dec_decode_hex_escape(js_ctx, 4);
34558                 break;
34559         }
34560 #if defined(DUK_USE_JX)
34561         case DUK_ASC_UC_U: {
34562                 if (js_ctx->flag_ext_custom) {
34563                         cp = duk__dec_decode_hex_escape(js_ctx, 8);
34564                 } else {
34565                         return 1;  /* syntax error */
34566                 }
34567                 break;
34568         }
34569         case DUK_ASC_LC_X: {
34570                 if (js_ctx->flag_ext_custom) {
34571                         cp = duk__dec_decode_hex_escape(js_ctx, 2);
34572                 } else {
34573                         return 1;  /* syntax error */
34574                 }
34575                 break;
34576         }
34577 #endif  /* DUK_USE_JX */
34578         default:
34579                 /* catches EOF (0x00) */
34580                 return 1;  /* syntax error */
34581         }
34582
34583         DUK_RAW_WRITE_XUTF8(*ext_p, cp);
34584
34585         return 0;
34586 }
34587
34588 DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
34589         duk_hthread *thr = js_ctx->thr;
34590         duk_bufwriter_ctx bw_alloc;
34591         duk_bufwriter_ctx *bw;
34592         duk_uint8_t *q;
34593
34594         /* '"' was eaten by caller */
34595
34596         /* Note that we currently parse -bytes-, not codepoints.
34597          * All non-ASCII extended UTF-8 will encode to bytes >= 0x80,
34598          * so they'll simply pass through (valid UTF-8 or not).
34599          */
34600
34601         bw = &bw_alloc;
34602         DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE);
34603         q = DUK_BW_GET_PTR(js_ctx->thr, bw);
34604
34605 #if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
34606         for (;;) {
34607                 duk_small_uint_t safe;
34608                 duk_uint8_t b, x;
34609                 const duk_uint8_t *p;
34610
34611                 /* Select a safe loop count where no output checks are
34612                  * needed assuming we won't encounter escapes.  Input
34613                  * bound checks are not necessary as a NUL (guaranteed)
34614                  * will cause a SyntaxError before we read out of bounds.
34615                  */
34616
34617                 safe = DUK__JSON_DECSTR_CHUNKSIZE;
34618
34619                 /* Ensure space for 1:1 output plus one escape. */
34620                 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q);
34621
34622                 p = js_ctx->p;  /* temp copy, write back for next loop */
34623                 for (;;) {
34624                         if (safe == 0) {
34625                                 js_ctx->p = p;
34626                                 break;
34627                         }
34628                         safe--;
34629
34630                         /* End of input (NUL) goes through slow path and causes SyntaxError. */
34631                         DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00);
34632
34633                         b = *p++;
34634                         x = (duk_small_int_t) duk__json_decstr_lookup[b];
34635                         if (DUK_LIKELY(x != 0)) {
34636                                 /* Fast path, decode as is. */
34637                                 *q++ = b;
34638                         } else if (b == DUK_ASC_DOUBLEQUOTE) {
34639                                 js_ctx->p = p;
34640                                 goto found_quote;
34641                         } else if (b == DUK_ASC_BACKSLASH) {
34642                                 /* We've ensured space for one escaped input; then
34643                                  * bail out and recheck (this makes escape handling
34644                                  * quite slow but it's uncommon).
34645                                  */
34646                                 js_ctx->p = p;
34647                                 if (duk__dec_string_escape(js_ctx, &q) != 0) {
34648                                         goto syntax_error;
34649                                 }
34650                                 break;
34651                         } else {
34652                                 js_ctx->p = p;
34653                                 goto syntax_error;
34654                         }
34655                 }
34656         }
34657  found_quote:
34658 #else  /* DUK_USE_JSON_DECSTRING_FASTPATH */
34659         for (;;) {
34660                 duk_uint8_t x;
34661
34662                 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q);
34663
34664                 x = duk__dec_get(js_ctx);
34665
34666                 if (x == DUK_ASC_DOUBLEQUOTE) {
34667                         break;
34668                 } else if (x == DUK_ASC_BACKSLASH) {
34669                         if (duk__dec_string_escape(js_ctx, &q) != 0) {
34670                                 goto syntax_error;
34671                         }
34672                 } else if (x < 0x20) {
34673                         /* catches EOF (NUL) */
34674                         goto syntax_error;
34675                 } else {
34676                         *q++ = (duk_uint8_t) x;
34677                 }
34678         }
34679 #endif  /* DUK_USE_JSON_DECSTRING_FASTPATH */
34680
34681         DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
34682         (void) duk_buffer_to_string(thr, -1);  /* Safe if input string is safe. */
34683
34684         /* [ ... str ] */
34685
34686         return;
34687
34688  syntax_error:
34689         duk__dec_syntax_error(js_ctx);
34690         DUK_UNREACHABLE();
34691 }
34692
34693 #if defined(DUK_USE_JX)
34694 /* Decode a plain string consisting entirely of identifier characters.
34695  * Used to parse plain keys (e.g. "foo: 123").
34696  */
34697 DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
34698         duk_hthread *thr = js_ctx->thr;
34699         const duk_uint8_t *p;
34700         duk_small_int_t x;
34701
34702         /* Caller has already eaten the first char so backtrack one byte. */
34703
34704         js_ctx->p--;  /* safe */
34705         p = js_ctx->p;
34706
34707         /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of
34708          * parsing (which is correct except if there are non-shortest encodings).
34709          * There is also no need to check explicitly for end of input buffer as
34710          * the input is NUL padded and NUL will exit the parsing loop.
34711          *
34712          * Because no unescaping takes place, we can just scan to the end of the
34713          * plain string and intern from the input buffer.
34714          */
34715
34716         for (;;) {
34717                 x = *p;
34718
34719                 /* There is no need to check the first character specially here
34720                  * (i.e. reject digits): the caller only accepts valid initial
34721                  * characters and won't call us if the first character is a digit.
34722                  * This also ensures that the plain string won't be empty.
34723                  */
34724
34725                 if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) {
34726                         break;
34727                 }
34728                 p++;
34729         }
34730
34731         duk_push_lstring(thr, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
34732         js_ctx->p = p;
34733
34734         /* [ ... str ] */
34735 }
34736 #endif  /* DUK_USE_JX */
34737
34738 #if defined(DUK_USE_JX)
34739 DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
34740         duk_hthread *thr = js_ctx->thr;
34741         const duk_uint8_t *p;
34742         duk_small_int_t x;
34743         void *voidptr;
34744
34745         /* Caller has already eaten the first character ('(') which we don't need. */
34746
34747         p = js_ctx->p;
34748
34749         for (;;) {
34750                 x = *p;
34751
34752                 /* Assume that the native representation never contains a closing
34753                  * parenthesis.
34754                  */
34755
34756                 if (x == DUK_ASC_RPAREN) {
34757                         break;
34758                 } else if (x <= 0) {
34759                         /* NUL term or -1 (EOF), NUL check would suffice */
34760                         goto syntax_error;
34761                 }
34762                 p++;
34763         }
34764
34765         /* There is no need to NUL delimit the sscanf() call: trailing garbage is
34766          * ignored and there is always a NUL terminator which will force an error
34767          * if no error is encountered before it.  It's possible that the scan
34768          * would scan further than between [js_ctx->p,p[ though and we'd advance
34769          * by less than the scanned value.
34770          *
34771          * Because pointers are platform specific, a failure to scan a pointer
34772          * results in a null pointer which is a better placeholder than a missing
34773          * value or an error.
34774          */
34775
34776         voidptr = NULL;
34777         (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
34778         duk_push_pointer(thr, voidptr);
34779         js_ctx->p = p + 1;  /* skip ')' */
34780
34781         /* [ ... ptr ] */
34782
34783         return;
34784
34785  syntax_error:
34786         duk__dec_syntax_error(js_ctx);
34787         DUK_UNREACHABLE();
34788 }
34789 #endif  /* DUK_USE_JX */
34790
34791 #if defined(DUK_USE_JX)
34792 DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
34793         duk_hthread *thr = js_ctx->thr;
34794         const duk_uint8_t *p;
34795         duk_uint8_t *buf;
34796         duk_size_t src_len;
34797         duk_small_int_t x;
34798
34799         /* Caller has already eaten the first character ('|') which we don't need. */
34800
34801         p = js_ctx->p;
34802
34803         /* XXX: Would be nice to share the fast path loop from duk_hex_decode()
34804          * and avoid creating a temporary buffer.  However, there are some
34805          * differences which prevent trivial sharing:
34806          *
34807          *   - Pipe char detection
34808          *   - EOF detection
34809          *   - Unknown length of input and output
34810          *
34811          * The best approach here would be a bufwriter and a reasonaly sized
34812          * safe inner loop (e.g. 64 output bytes at a time).
34813          */
34814
34815         for (;;) {
34816                 x = *p;
34817
34818                 /* This loop intentionally does not ensure characters are valid
34819                  * ([0-9a-fA-F]) because the hex decode call below will do that.
34820                  */
34821                 if (x == DUK_ASC_PIPE) {
34822                         break;
34823                 } else if (x <= 0) {
34824                         /* NUL term or -1 (EOF), NUL check would suffice */
34825                         goto syntax_error;
34826                 }
34827                 p++;
34828         }
34829
34830         /* XXX: this is not very nice; unnecessary copy is made. */
34831         src_len = (duk_size_t) (p - js_ctx->p);
34832         buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, src_len);
34833         DUK_ASSERT(buf != NULL);
34834         duk_memcpy((void *) buf, (const void *) js_ctx->p, src_len);
34835         duk_hex_decode(thr, -1);
34836
34837         js_ctx->p = p + 1;  /* skip '|' */
34838
34839         /* [ ... buf ] */
34840
34841         return;
34842
34843  syntax_error:
34844         duk__dec_syntax_error(js_ctx);
34845         DUK_UNREACHABLE();
34846 }
34847 #endif  /* DUK_USE_JX */
34848
34849 /* Parse a number, other than NaN or +/- Infinity */
34850 DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
34851         duk_hthread *thr = js_ctx->thr;
34852         const duk_uint8_t *p_start;
34853         const duk_uint8_t *p;
34854         duk_uint8_t x;
34855         duk_small_uint_t s2n_flags;
34856
34857         DUK_DDD(DUK_DDDPRINT("parse_number"));
34858
34859         p_start = js_ctx->p;
34860
34861         /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a
34862          * string for strict number parsing.
34863          */
34864
34865         p = js_ctx->p;
34866         for (;;) {
34867                 x = *p;
34868
34869                 DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld",
34870                                      (const void *) p_start, (const void *) p,
34871                                      (const void *) js_ctx->p_end, (long) x));
34872
34873 #if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
34874                 /* This fast path is pretty marginal in practice.
34875                  * XXX: candidate for removal.
34876                  */
34877                 DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00);  /* end-of-input breaks */
34878                 if (duk__json_decnumber_lookup[x] == 0) {
34879                         break;
34880                 }
34881 #else  /* DUK_USE_JSON_DECNUMBER_FASTPATH */
34882                 if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
34883                       (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E ||
34884                        x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) {
34885                         /* Plus sign must be accepted for positive exponents
34886                          * (e.g. '1.5e+2').  This clause catches NULs.
34887                          */
34888                         break;
34889                 }
34890 #endif  /* DUK_USE_JSON_DECNUMBER_FASTPATH */
34891                 p++;  /* safe, because matched (NUL causes a break) */
34892         }
34893         js_ctx->p = p;
34894
34895         DUK_ASSERT(js_ctx->p > p_start);
34896         duk_push_lstring(thr, (const char *) p_start, (duk_size_t) (p - p_start));
34897
34898         s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
34899                     DUK_S2N_FLAG_ALLOW_MINUS |  /* but don't allow leading plus */
34900                     DUK_S2N_FLAG_ALLOW_FRAC;
34901
34902         DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
34903                              (duk_tval *) duk_get_tval(thr, -1)));
34904         duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
34905         if (duk_is_nan(thr, -1)) {
34906                 duk__dec_syntax_error(js_ctx);
34907         }
34908         DUK_ASSERT(duk_is_number(thr, -1));
34909         DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
34910                              (duk_tval *) duk_get_tval(thr, -1)));
34911
34912         /* [ ... num ] */
34913 }
34914
34915 DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
34916         duk_hthread *thr = js_ctx->thr;
34917         duk_require_stack(thr, DUK_JSON_DEC_REQSTACK);
34918
34919         /* c recursion check */
34920
34921         DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0);  /* unsigned */
34922         DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
34923         if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
34924                 DUK_ERROR_RANGE(thr, DUK_STR_JSONDEC_RECLIMIT);
34925                 DUK_WO_NORETURN(return;);
34926         }
34927         js_ctx->recursion_depth++;
34928 }
34929
34930 DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
34931         /* c recursion check */
34932
34933         DUK_ASSERT(js_ctx->recursion_depth > 0);
34934         DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
34935         js_ctx->recursion_depth--;
34936 }
34937
34938 DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
34939         duk_hthread *thr = js_ctx->thr;
34940         duk_int_t key_count;  /* XXX: a "first" flag would suffice */
34941         duk_uint8_t x;
34942
34943         DUK_DDD(DUK_DDDPRINT("parse_object"));
34944
34945         duk__dec_objarr_entry(js_ctx);
34946
34947         duk_push_object(thr);
34948
34949         /* Initial '{' has been checked and eaten by caller. */
34950
34951         key_count = 0;
34952         for (;;) {
34953                 x = duk__dec_get_nonwhite(js_ctx);
34954
34955                 DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
34956                                      (duk_tval *) duk_get_tval(thr, -1),
34957                                      (long) x, (long) key_count));
34958
34959                 /* handle comma and closing brace */
34960
34961                 if (x == DUK_ASC_COMMA && key_count > 0) {
34962                         /* accept comma, expect new value */
34963                         x = duk__dec_get_nonwhite(js_ctx);
34964                 } else if (x == DUK_ASC_RCURLY) {
34965                         /* eat closing brace */
34966                         break;
34967                 } else if (key_count == 0) {
34968                         /* accept anything, expect first value (EOF will be
34969                          * caught by key parsing below.
34970                          */
34971                         ;
34972                 } else {
34973                         /* catches EOF (NUL) and initial comma */
34974                         goto syntax_error;
34975                 }
34976
34977                 /* parse key and value */
34978
34979                 if (x == DUK_ASC_DOUBLEQUOTE) {
34980                         duk__dec_string(js_ctx);
34981 #if defined(DUK_USE_JX)
34982                 } else if (js_ctx->flag_ext_custom &&
34983                            duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
34984                         duk__dec_plain_string(js_ctx);
34985 #endif
34986                 } else {
34987                         goto syntax_error;
34988                 }
34989
34990                 /* [ ... obj key ] */
34991
34992                 x = duk__dec_get_nonwhite(js_ctx);
34993                 if (x != DUK_ASC_COLON) {
34994                         goto syntax_error;
34995                 }
34996
34997                 duk__dec_value(js_ctx);
34998
34999                 /* [ ... obj key val ] */
35000
35001                 duk_xdef_prop_wec(thr, -3);
35002
35003                 /* [ ... obj ] */
35004
35005                 key_count++;
35006         }
35007
35008         /* [ ... obj ] */
35009
35010         DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
35011                              (duk_tval *) duk_get_tval(thr, -1)));
35012
35013         duk__dec_objarr_exit(js_ctx);
35014         return;
35015
35016  syntax_error:
35017         duk__dec_syntax_error(js_ctx);
35018         DUK_UNREACHABLE();
35019 }
35020
35021 DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
35022         duk_hthread *thr = js_ctx->thr;
35023         duk_uarridx_t arr_idx;
35024         duk_uint8_t x;
35025
35026         DUK_DDD(DUK_DDDPRINT("parse_array"));
35027
35028         duk__dec_objarr_entry(js_ctx);
35029
35030         duk_push_array(thr);
35031
35032         /* Initial '[' has been checked and eaten by caller. */
35033
35034         arr_idx = 0;
35035         for (;;) {
35036                 x = duk__dec_get_nonwhite(js_ctx);
35037
35038                 DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
35039                                      (duk_tval *) duk_get_tval(thr, -1),
35040                                      (long) x, (long) arr_idx));
35041
35042                 /* handle comma and closing bracket */
35043
35044                 if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) {
35045                         /* accept comma, expect new value */
35046                         ;
35047                 } else if (x == DUK_ASC_RBRACKET) {
35048                         /* eat closing bracket */
35049                         break;
35050                 } else if (arr_idx == 0) {
35051                         /* accept anything, expect first value (EOF will be
35052                          * caught by duk__dec_value() below.
35053                          */
35054                         js_ctx->p--;  /* backtrack (safe) */
35055                 } else {
35056                         /* catches EOF (NUL) and initial comma */
35057                         goto syntax_error;
35058                 }
35059
35060                 /* parse value */
35061
35062                 duk__dec_value(js_ctx);
35063
35064                 /* [ ... arr val ] */
35065
35066                 duk_xdef_prop_index_wec(thr, -2, arr_idx);
35067                 arr_idx++;
35068         }
35069
35070         /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to
35071          * set the values.
35072          */
35073
35074         duk_set_length(thr, -1, arr_idx);
35075
35076         /* [ ... arr ] */
35077
35078         DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
35079                              (duk_tval *) duk_get_tval(thr, -1)));
35080
35081         duk__dec_objarr_exit(js_ctx);
35082         return;
35083
35084  syntax_error:
35085         duk__dec_syntax_error(js_ctx);
35086         DUK_UNREACHABLE();
35087 }
35088
35089 DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
35090         duk_hthread *thr = js_ctx->thr;
35091         duk_uint8_t x;
35092
35093         x = duk__dec_get_nonwhite(js_ctx);
35094
35095         DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x));
35096
35097         /* Note: duk__dec_req_stridx() backtracks one char */
35098
35099         if (x == DUK_ASC_DOUBLEQUOTE) {
35100                 duk__dec_string(js_ctx);
35101         } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
35102 #if defined(DUK_USE_JX)
35103                 if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
35104                         duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY);  /* "-Infinity", '-' has been eaten */
35105                         duk_push_number(thr, -DUK_DOUBLE_INFINITY);
35106                 } else {
35107 #else
35108                 {  /* unconditional block */
35109 #endif
35110                         /* We already ate 'x', so backup one byte. */
35111                         js_ctx->p--;  /* safe */
35112                         duk__dec_number(js_ctx);
35113                 }
35114         } else if (x == DUK_ASC_LC_T) {
35115                 duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
35116                 duk_push_true(thr);
35117         } else if (x == DUK_ASC_LC_F) {
35118                 duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
35119                 duk_push_false(thr);
35120         } else if (x == DUK_ASC_LC_N) {
35121                 duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
35122                 duk_push_null(thr);
35123 #if defined(DUK_USE_JX)
35124         } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
35125                 duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
35126                 duk_push_undefined(thr);
35127         } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
35128                 duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
35129                 duk_push_nan(thr);
35130         } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
35131                 duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
35132                 duk_push_number(thr, DUK_DOUBLE_INFINITY);
35133         } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
35134                 duk__dec_pointer(js_ctx);
35135         } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
35136                 duk__dec_buffer(js_ctx);
35137 #endif
35138         } else if (x == DUK_ASC_LCURLY) {
35139                 duk__dec_object(js_ctx);
35140         } else if (x == DUK_ASC_LBRACKET) {
35141                 duk__dec_array(js_ctx);
35142         } else {
35143                 /* catches EOF (NUL) */
35144                 goto syntax_error;
35145         }
35146
35147         duk__dec_eat_white(js_ctx);
35148
35149         /* [ ... val ] */
35150         return;
35151
35152  syntax_error:
35153         duk__dec_syntax_error(js_ctx);
35154         DUK_UNREACHABLE();
35155 }
35156
35157 /* Recursive value reviver, implements the Walk() algorithm.  No C recursion
35158  * check is done here because the initial parsing step will already ensure
35159  * there is a reasonable limit on C recursion depth and hence object depth.
35160  */
35161 DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
35162         duk_hthread *thr = js_ctx->thr;
35163         duk_hobject *h;
35164         duk_uarridx_t i, arr_len;
35165
35166         DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
35167                              (long) duk_get_top(thr),
35168                              (duk_tval *) duk_get_tval(thr, -2),
35169                              (duk_tval *) duk_get_tval(thr, -1)));
35170
35171         duk_dup_top(thr);
35172         duk_get_prop(thr, -3);  /* -> [ ... holder name val ] */
35173
35174         h = duk_get_hobject(thr, -1);
35175         if (h != NULL) {
35176                 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
35177                         arr_len = (duk_uarridx_t) duk_get_length(thr, -1);
35178                         for (i = 0; i < arr_len; i++) {
35179                                 /* [ ... holder name val ] */
35180
35181                                 DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
35182                                                      (long) duk_get_top(thr), (long) i, (long) arr_len,
35183                                                      (duk_tval *) duk_get_tval(thr, -3), (duk_tval *) duk_get_tval(thr, -2),
35184                                                      (duk_tval *) duk_get_tval(thr, -1)));
35185
35186                                 duk_dup_top(thr);
35187                                 (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i);  /* -> [ ... holder name val val ToString(i) ] */
35188                                 duk__dec_reviver_walk(js_ctx);  /* -> [ ... holder name val new_elem ] */
35189
35190                                 if (duk_is_undefined(thr, -1)) {
35191                                         duk_pop(thr);
35192                                         duk_del_prop_index(thr, -1, i);
35193                                 } else {
35194                                         /* XXX: duk_xdef_prop_index_wec() would be more appropriate
35195                                          * here but it currently makes some assumptions that might
35196                                          * not hold (e.g. that previous property is not an accessor).
35197                                          */
35198                                         duk_put_prop_index(thr, -2, i);
35199                                 }
35200                         }
35201                 } else {
35202                         /* [ ... holder name val ] */
35203                         duk_enum(thr, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
35204                         while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
35205                                 DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
35206                                                      (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -5),
35207                                                      (duk_tval *) duk_get_tval(thr, -4), (duk_tval *) duk_get_tval(thr, -3),
35208                                                      (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
35209
35210                                 /* [ ... holder name val enum obj_key ] */
35211                                 duk_dup_m3(thr);
35212                                 duk_dup_m2(thr);
35213
35214                                 /* [ ... holder name val enum obj_key val obj_key ] */
35215                                 duk__dec_reviver_walk(js_ctx);
35216
35217                                 /* [ ... holder name val enum obj_key new_elem ] */
35218                                 if (duk_is_undefined(thr, -1)) {
35219                                         duk_pop(thr);
35220                                         duk_del_prop(thr, -3);
35221                                 } else {
35222                                         /* XXX: duk_xdef_prop_index_wec() would be more appropriate
35223                                          * here but it currently makes some assumptions that might
35224                                          * not hold (e.g. that previous property is not an accessor).
35225                                          *
35226                                          * Using duk_put_prop() works incorrectly with '__proto__'
35227                                          * if the own property with that name has been deleted.  This
35228                                          * does not happen normally, but a clever reviver can trigger
35229                                          * that, see complex reviver case in: test-bug-json-parse-__proto__.js.
35230                                          */
35231                                         duk_put_prop(thr, -4);
35232                                 }
35233                         }
35234                         duk_pop(thr);  /* pop enum */
35235                 }
35236         }
35237
35238         /* [ ... holder name val ] */
35239
35240         duk_dup(thr, js_ctx->idx_reviver);
35241         duk_insert(thr, -4);  /* -> [ ... reviver holder name val ] */
35242         duk_call_method(thr, 2);  /* -> [ ... res ] */
35243
35244         DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
35245                              (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, -1)));
35246 }
35247
35248 /*
35249  *  Stringify implementation.
35250  */
35251
35252 #define DUK__EMIT_1(js_ctx,ch)          duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch))
35253 #define DUK__EMIT_2(js_ctx,ch1,ch2)     duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2))
35254 #define DUK__EMIT_HSTR(js_ctx,h)        duk__emit_hstring((js_ctx), (h))
35255 #if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
35256 #define DUK__EMIT_CSTR(js_ctx,p)        duk__emit_cstring((js_ctx), (p))
35257 #endif
35258 #define DUK__EMIT_STRIDX(js_ctx,i)      duk__emit_stridx((js_ctx), (i))
35259 #define DUK__UNEMIT_1(js_ctx)           duk__unemit_1((js_ctx))
35260
35261 DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) {
35262         DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch);
35263 }
35264
35265 DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) {
35266         DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2);
35267 }
35268
35269 DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) {
35270         DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
35271 }
35272
35273 #if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
35274 DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) {
35275         DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str);
35276 }
35277 #endif
35278
35279 DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) {
35280         duk_hstring *h;
35281
35282         DUK_ASSERT_STRIDX_VALID(stridx);
35283         h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
35284         DUK_ASSERT(h != NULL);
35285
35286         DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
35287 }
35288
35289 DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) {
35290         DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1);
35291         DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1);
35292 }
35293
35294 #define DUK__MKESC(nybbles,esc1,esc2)  \
35295         (((duk_uint_fast32_t) (nybbles)) << 16) | \
35296         (((duk_uint_fast32_t) (esc1)) << 8) | \
35297         ((duk_uint_fast32_t) (esc2))
35298
35299 DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) {
35300         duk_uint_fast32_t tmp;
35301         duk_small_uint_t dig;
35302
35303         DUK_UNREF(js_ctx);
35304
35305         /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */
35306
35307         /* Select appropriate escape format automatically, and set 'tmp' to a
35308          * value encoding both the escape format character and the nybble count:
35309          *
35310          *   (nybble_count << 16) | (escape_char1) | (escape_char2)
35311          */
35312
35313 #if defined(DUK_USE_JX)
35314         if (DUK_LIKELY(cp < 0x100UL)) {
35315                 if (DUK_UNLIKELY(js_ctx->flag_ext_custom != 0U)) {
35316                         tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
35317                 } else {
35318                         tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
35319                 }
35320         } else
35321 #endif
35322         if (DUK_LIKELY(cp < 0x10000UL)) {
35323                 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
35324         } else {
35325 #if defined(DUK_USE_JX)
35326                 if (DUK_LIKELY(js_ctx->flag_ext_custom != 0U)) {
35327                         tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
35328                 } else
35329 #endif
35330                 {
35331                         /* In compatible mode and standard JSON mode, output
35332                          * something useful for non-BMP characters.  This won't
35333                          * roundtrip but will still be more or less readable and
35334                          * more useful than an error.
35335                          */
35336                         tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS);
35337                 }
35338         }
35339
35340         *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff);
35341         *q++ = (duk_uint8_t) (tmp & 0xff);
35342
35343         tmp = tmp >> 16;
35344         while (tmp > 0) {
35345                 tmp--;
35346                 dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f);
35347                 *q++ = duk_lc_digits[dig];
35348         }
35349
35350         return q;
35351 }
35352
35353 DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
35354         const duk_int8_t *p, *p_start, *p_end;  /* Note: intentionally signed. */
35355         duk_size_t k_len;
35356         duk_codepoint_t cp;
35357
35358         DUK_ASSERT(k != NULL);
35359
35360         /* Accept ASCII strings which conform to identifier requirements
35361          * as being emitted without key quotes.  Since we only accept ASCII
35362          * there's no need for actual decoding: 'p' is intentionally signed
35363          * so that bytes >= 0x80 extend to negative values and are rejected
35364          * as invalid identifier codepoints.
35365          */
35366
35367         if (js_ctx->flag_avoid_key_quotes) {
35368                 k_len = DUK_HSTRING_GET_BYTELEN(k);
35369                 p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k);
35370                 p_end = p_start + k_len;
35371                 p = p_start;
35372
35373                 if (p == p_end) {
35374                         /* Zero length string is not accepted without quotes */
35375                         goto quote_normally;
35376                 }
35377                 cp = (duk_codepoint_t) (*p++);
35378                 if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) {
35379                         goto quote_normally;
35380                 }
35381                 while (p < p_end) {
35382                         cp = (duk_codepoint_t) (*p++);
35383                         if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) {
35384                                 goto quote_normally;
35385                         }
35386                 }
35387
35388                 /* This seems faster than emitting bytes one at a time and
35389                  * then potentially rewinding.
35390                  */
35391                 DUK__EMIT_HSTR(js_ctx, k);
35392                 return;
35393         }
35394
35395  quote_normally:
35396         duk__enc_quote_string(js_ctx, k);
35397 }
35398
35399 /* The Quote(value) operation: quote a string.
35400  *
35401  * Stack policy: [ ] -> [ ].
35402  */
35403
35404 DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
35405         duk_hthread *thr = js_ctx->thr;
35406         const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp;
35407         duk_uint8_t *q;
35408         duk_ucodepoint_t cp;  /* typed for duk_unicode_decode_xutf8() */
35409
35410         DUK_DDD(DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str));
35411
35412         DUK_ASSERT(h_str != NULL);
35413         p_start = DUK_HSTRING_GET_DATA(h_str);
35414         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str);
35415         p = p_start;
35416
35417         DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
35418
35419         /* Encode string in small chunks, estimating the maximum expansion so that
35420          * there's no need to ensure space while processing the chunk.
35421          */
35422
35423         while (p < p_end) {
35424                 duk_size_t left, now, space;
35425
35426                 left = (duk_size_t) (p_end - p);
35427                 now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ?
35428                        DUK__JSON_ENCSTR_CHUNKSIZE : left);
35429
35430                 /* Maximum expansion per input byte is 6:
35431                  *   - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6).
35432                  *   - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3).
35433                  *   - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5).
35434                  */
35435                 space = now * 6;
35436                 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
35437
35438                 p_now = p + now;
35439
35440                 while (p < p_now) {
35441 #if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
35442                         duk_uint8_t b;
35443
35444                         b = duk__json_quotestr_lookup[*p++];
35445                         if (DUK_LIKELY(b < 0x80)) {
35446                                 /* Most input bytes go through here. */
35447                                 *q++ = b;
35448                         } else if (b >= 0xa0) {
35449                                 *q++ = DUK_ASC_BACKSLASH;
35450                                 *q++ = (duk_uint8_t) (b - 0x80);
35451                         } else if (b == 0x80) {
35452                                 cp = (duk_ucodepoint_t) (*(p - 1));
35453                                 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
35454                         } else if (b == 0x7f && js_ctx->flag_ascii_only) {
35455                                 /* 0x7F is special */
35456                                 DUK_ASSERT(b == 0x81);
35457                                 cp = (duk_ucodepoint_t) 0x7f;
35458                                 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
35459                         } else {
35460                                 DUK_ASSERT(b == 0x81);
35461                                 p--;
35462
35463                                 /* slow path is shared */
35464 #else  /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
35465                         cp = *p;
35466
35467                         if (DUK_LIKELY(cp <= 0x7f)) {
35468                                 /* ascii fast path: avoid decoding utf-8 */
35469                                 p++;
35470                                 if (cp == 0x22 || cp == 0x5c) {
35471                                         /* double quote or backslash */
35472                                         *q++ = DUK_ASC_BACKSLASH;
35473                                         *q++ = (duk_uint8_t) cp;
35474                                 } else if (cp < 0x20) {
35475                                         duk_uint_fast8_t esc_char;
35476
35477                                         /* This approach is a bit shorter than a straight
35478                                          * if-else-ladder and also a bit faster.
35479                                          */
35480                                         if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) &&
35481                                             (esc_char = duk__json_quotestr_esc[cp]) != 0) {
35482                                                 *q++ = DUK_ASC_BACKSLASH;
35483                                                 *q++ = (duk_uint8_t) esc_char;
35484                                         } else {
35485                                                 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
35486                                         }
35487                                 } else if (cp == 0x7f && js_ctx->flag_ascii_only) {
35488                                         q = duk__emit_esc_auto_fast(js_ctx, cp, q);
35489                                 } else {
35490                                         /* any other printable -> as is */
35491                                         *q++ = (duk_uint8_t) cp;
35492                                 }
35493                         } else {
35494                                 /* slow path is shared */
35495 #endif  /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
35496
35497                                 /* slow path decode */
35498
35499                                 /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly
35500                                  * and go forward one byte.  This is of course very lossy, but allows some kind
35501                                  * of output to be produced even for internal strings which don't conform to
35502                                  * XUTF-8.  All standard ECMAScript strings are always CESU-8, so this behavior
35503                                  * does not violate the ECMAScript specification.  The behavior is applied to
35504                                  * all modes, including ECMAScript standard JSON.  Because the current XUTF-8
35505                                  * decoding is not very strict, this behavior only really affects initial bytes
35506                                  * and truncated codepoints.
35507                                  *
35508                                  * Another alternative would be to scan forwards to start of next codepoint
35509                                  * (or end of input) and emit just one replacement codepoint.
35510                                  */
35511
35512                                 p_tmp = p;
35513                                 if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
35514                                         /* Decode failed. */
35515                                         cp = *p_tmp;
35516                                         p = p_tmp + 1;
35517                                 }
35518
35519 #if defined(DUK_USE_NONSTD_JSON_ESC_U2028_U2029)
35520                                 if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) {
35521 #else
35522                                 if (js_ctx->flag_ascii_only) {
35523 #endif
35524                                         q = duk__emit_esc_auto_fast(js_ctx, cp, q);
35525                                 } else {
35526                                         /* as is */
35527                                         DUK_RAW_WRITE_XUTF8(q, cp);
35528                                 }
35529                         }
35530                 }
35531
35532                 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
35533         }
35534
35535         DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
35536 }
35537
35538 /* Encode a double (checked by caller) from stack top.  Stack top may be
35539  * replaced by serialized string but is not popped (caller does that).
35540  */
35541 DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
35542         duk_hthread *thr;
35543         duk_tval *tv;
35544         duk_double_t d;
35545         duk_small_int_t c;
35546         duk_small_int_t s;
35547         duk_small_uint_t stridx;
35548         duk_small_uint_t n2s_flags;
35549         duk_hstring *h_str;
35550
35551         DUK_ASSERT(js_ctx != NULL);
35552         thr = js_ctx->thr;
35553         DUK_ASSERT(thr != NULL);
35554
35555         /* Caller must ensure 'tv' is indeed a double and not a fastint! */
35556         tv = DUK_GET_TVAL_NEGIDX(thr, -1);
35557         DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
35558         d = DUK_TVAL_GET_DOUBLE(tv);
35559
35560         c = (duk_small_int_t) DUK_FPCLASSIFY(d);
35561         s = (duk_small_int_t) DUK_SIGNBIT(d);
35562         DUK_UNREF(s);
35563
35564         if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) {
35565                 DUK_ASSERT(DUK_ISFINITE(d));
35566
35567 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
35568                 /* Negative zero needs special handling in JX/JC because
35569                  * it would otherwise serialize to '0', not '-0'.
35570                  */
35571                 if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
35572                                  (js_ctx->flag_ext_custom_or_compatible))) {
35573                         duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_ZERO);  /* '-0' */
35574                 } else
35575 #endif  /* DUK_USE_JX || DUK_USE_JC */
35576                 {
35577                         n2s_flags = 0;
35578                         /* [ ... number ] -> [ ... string ] */
35579                         duk_numconv_stringify(thr, 10 /*radix*/, 0 /*digits*/, n2s_flags);
35580                 }
35581                 h_str = duk_known_hstring(thr, -1);
35582                 DUK__EMIT_HSTR(js_ctx, h_str);
35583                 return;
35584         }
35585
35586 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
35587         if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
35588                                DUK_JSON_FLAG_EXT_COMPATIBLE))) {
35589                 stridx = DUK_STRIDX_LC_NULL;
35590         } else if (c == DUK_FP_NAN) {
35591                 stridx = js_ctx->stridx_custom_nan;
35592         } else if (s == 0) {
35593                 stridx = js_ctx->stridx_custom_posinf;
35594         } else {
35595                 stridx = js_ctx->stridx_custom_neginf;
35596         }
35597 #else
35598         stridx = DUK_STRIDX_LC_NULL;
35599 #endif
35600         DUK__EMIT_STRIDX(js_ctx, stridx);
35601 }
35602
35603 #if defined(DUK_USE_FASTINT)
35604 /* Encode a fastint from duk_tval ptr, no value stack effects. */
35605 DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
35606         duk_int64_t v;
35607
35608         /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328
35609          * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808
35610          * (20 chars long).  Alloc space for 64-bit range to be safe.
35611          */
35612         duk_uint8_t buf[20 + 1];
35613
35614         /* Caller must ensure 'tv' is indeed a fastint! */
35615         DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
35616         v = DUK_TVAL_GET_FASTINT(tv);
35617
35618         /* XXX: There are no format strings in duk_config.h yet, could add
35619          * one for formatting duk_int64_t.  For now, assumes "%lld" and that
35620          * "long long" type exists.  Could also rely on C99 directly but that
35621          * won't work for older MSVC.
35622          */
35623         DUK_SPRINTF((char *) buf, "%lld", (long long) v);
35624         DUK__EMIT_CSTR(js_ctx, (const char *) buf);
35625 }
35626 #endif
35627
35628 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
35629 #if defined(DUK_USE_HEX_FASTPATH)
35630 DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
35631         duk_uint8_t *q;
35632         duk_uint16_t *q16;
35633         duk_small_uint_t x;
35634         duk_size_t i, len_safe;
35635 #if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
35636         duk_bool_t shift_dst;
35637 #endif
35638
35639         /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2.
35640          * For platforms where unaligned accesses are not allowed, shift 'dst'
35641          * ahead by 1 byte to get alignment and then duk_memmove() the result
35642          * in place.  The faster encoding loop makes up the difference.
35643          * There's always space for one extra byte because a terminator always
35644          * follows the hex data and that's been accounted for by the caller.
35645          */
35646
35647 #if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
35648         q16 = (duk_uint16_t *) (void *) dst;
35649 #else
35650         shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U);
35651         if (shift_dst) {
35652                 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1"));
35653                 q16 = (duk_uint16_t *) (void *) (dst + 1);
35654         } else {
35655                 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned"));
35656                 q16 = (duk_uint16_t *) (void *) dst;
35657         }
35658         DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0);
35659 #endif
35660
35661         len_safe = src_len & ~0x03U;
35662         for (i = 0; i < len_safe; i += 4) {
35663                 q16[0] = duk_hex_enctab[src[i]];
35664                 q16[1] = duk_hex_enctab[src[i + 1]];
35665                 q16[2] = duk_hex_enctab[src[i + 2]];
35666                 q16[3] = duk_hex_enctab[src[i + 3]];
35667                 q16 += 4;
35668         }
35669         q = (duk_uint8_t *) q16;
35670
35671 #if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
35672         if (shift_dst) {
35673                 q--;
35674                 duk_memmove((void *) dst, (const void *) (dst + 1), 2 * len_safe);
35675                 DUK_ASSERT(dst + 2 * len_safe == q);
35676         }
35677 #endif
35678
35679         for (; i < src_len; i++) {
35680                 x = src[i];
35681                 *q++ = duk_lc_digits[x >> 4];
35682                 *q++ = duk_lc_digits[x & 0x0f];
35683         }
35684
35685         return q;
35686 }
35687 #else  /* DUK_USE_HEX_FASTPATH */
35688 DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
35689         const duk_uint8_t *p;
35690         const duk_uint8_t *p_end;
35691         duk_uint8_t *q;
35692         duk_small_uint_t x;
35693
35694         p = src;
35695         p_end = src + src_len;
35696         q = dst;
35697         while (p != p_end) {
35698                 x = *p++;
35699                 *q++ = duk_lc_digits[x >> 4];
35700                 *q++ = duk_lc_digits[x & 0x0f];
35701         }
35702
35703         return q;
35704 }
35705 #endif  /* DUK_USE_HEX_FASTPATH */
35706
35707 DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) {
35708         duk_hthread *thr;
35709         duk_uint8_t *q;
35710         duk_size_t space;
35711
35712         thr = js_ctx->thr;
35713
35714         DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);  /* caller checks */
35715         DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
35716
35717         /* Buffer values are encoded in (lowercase) hex to make the
35718          * binary data readable.  Base64 or similar would be more
35719          * compact but less readable, and the point of JX/JC
35720          * variants is to be as useful to a programmer as possible.
35721          */
35722
35723         /* The #if defined() clutter here needs to handle the three
35724          * cases: (1) JX+JC, (2) JX only, (3) JC only.
35725          */
35726
35727         /* Note: space must cater for both JX and JC. */
35728         space = 9 + buf_len * 2 + 2;
35729         DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL);
35730         DUK_ASSERT((space - 2) / 2 >= buf_len);  /* overflow not possible, buffer limits */
35731         q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
35732
35733 #if defined(DUK_USE_JX) && defined(DUK_USE_JC)
35734         if (js_ctx->flag_ext_custom)
35735 #endif
35736 #if defined(DUK_USE_JX)
35737         {
35738                 *q++ = DUK_ASC_PIPE;
35739                 q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
35740                 *q++ = DUK_ASC_PIPE;
35741
35742         }
35743 #endif
35744 #if defined(DUK_USE_JX) && defined(DUK_USE_JC)
35745         else
35746 #endif
35747 #if defined(DUK_USE_JC)
35748         {
35749                 DUK_ASSERT(js_ctx->flag_ext_compatible);
35750                 duk_memcpy((void *) q, (const void *) "{\"_buf\":\"", 9);  /* len: 9 */
35751                 q += 9;
35752                 q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
35753                 *q++ = DUK_ASC_DOUBLEQUOTE;
35754                 *q++ = DUK_ASC_RCURLY;
35755         }
35756 #endif
35757
35758         DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
35759 }
35760
35761 DUK_LOCAL void duk__enc_buffer_jx_jc(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
35762         duk__enc_buffer_data(js_ctx,
35763                              (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
35764                              (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
35765 }
35766 #endif  /* DUK_USE_JX || DUK_USE_JC */
35767
35768 #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
35769 DUK_LOCAL void duk__enc_buffer_json_fastpath(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
35770         duk_size_t i, n;
35771         const duk_uint8_t *buf;
35772         duk_uint8_t *q;
35773
35774         n = DUK_HBUFFER_GET_SIZE(h);
35775         if (n == 0) {
35776                 DUK__EMIT_2(js_ctx, DUK_ASC_LCURLY, DUK_ASC_RCURLY);
35777                 return;
35778         }
35779
35780         DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
35781
35782         /* Maximum encoded length with 32-bit index: 1 + 10 + 2 + 3 + 1 + 1 = 18,
35783          * with 64-bit index: 1 + 20 + 2 + 3 + 1 + 1 = 28.  32 has some slack.
35784          *
35785          * Note that because the output buffer is reallocated from time to time,
35786          * side effects (such as finalizers) affecting the buffer 'h' must be
35787          * disabled.  This is the case in the JSON.stringify() fast path.
35788          */
35789
35790         buf = (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h);
35791         if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
35792                 for (i = 0; i < n; i++) {
35793                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth + 1);
35794                         q = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, 32);
35795                         q += DUK_SPRINTF((char *) q, "\"%lu\": %u,", (unsigned long) i, (unsigned int) buf[i]);
35796                         DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
35797                 }
35798         } else {
35799                 q = DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw);
35800                 for (i = 0; i < n; i++) {
35801                         q = DUK_BW_ENSURE_RAW(js_ctx->thr, &js_ctx->bw, 32, q);
35802                         q += DUK_SPRINTF((char *) q, "\"%lu\":%u,", (unsigned long) i, (unsigned int) buf[i]);
35803                 }
35804                 DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, q);
35805         }
35806         DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
35807
35808         if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
35809                 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
35810         }
35811         DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
35812 }
35813 #endif  /* DUK_USE_JSON_STRINGIFY_FASTPATH */
35814
35815 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
35816 DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
35817         char buf[64];  /* XXX: how to figure correct size? */
35818         const char *fmt;
35819
35820         DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);  /* caller checks */
35821         DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
35822
35823         duk_memzero(buf, sizeof(buf));
35824
35825         /* The #if defined() clutter here needs to handle the three
35826          * cases: (1) JX+JC, (2) JX only, (3) JC only.
35827          */
35828 #if defined(DUK_USE_JX) && defined(DUK_USE_JC)
35829         if (js_ctx->flag_ext_custom)
35830 #endif
35831 #if defined(DUK_USE_JX)
35832         {
35833                 fmt = ptr ? "(%p)" : "(null)";
35834         }
35835 #endif
35836 #if defined(DUK_USE_JX) && defined(DUK_USE_JC)
35837         else
35838 #endif
35839 #if defined(DUK_USE_JC)
35840         {
35841                 DUK_ASSERT(js_ctx->flag_ext_compatible);
35842                 fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
35843         }
35844 #endif
35845
35846         /* When ptr == NULL, the format argument is unused. */
35847         DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr);  /* must not truncate */
35848         DUK__EMIT_CSTR(js_ctx, buf);
35849 }
35850 #endif  /* DUK_USE_JX || DUK_USE_JC */
35851
35852 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
35853 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
35854 DUK_LOCAL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) {
35855         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
35856
35857         if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
35858                 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
35859         } else {
35860                 /* Handle both full and partial slice (as long as covered). */
35861                 duk__enc_buffer_data(js_ctx,
35862                                      (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
35863                                      (duk_size_t) h_bufobj->length);
35864         }
35865 }
35866 #endif  /* DUK_USE_JX || DUK_USE_JC */
35867 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
35868
35869 /* Indent helper.  Calling code relies on js_ctx->recursion_depth also being
35870  * directly related to indent depth.
35871  */
35872 #if defined(DUK_USE_PREFER_SIZE)
35873 DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
35874         DUK_ASSERT(js_ctx->h_gap != NULL);
35875         DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0);  /* caller guarantees */
35876
35877         DUK__EMIT_1(js_ctx, 0x0a);
35878         while (depth-- > 0) {
35879                 DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap);
35880         }
35881 }
35882 #else  /* DUK_USE_PREFER_SIZE */
35883 DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_uint_t depth) {
35884         const duk_uint8_t *gap_data;
35885         duk_size_t gap_len;
35886         duk_size_t avail_bytes;   /* bytes of indent available for copying */
35887         duk_size_t need_bytes;    /* bytes of indent still needed */
35888         duk_uint8_t *p_start;
35889         duk_uint8_t *p;
35890
35891         DUK_ASSERT(js_ctx->h_gap != NULL);
35892         DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0);  /* caller guarantees */
35893
35894         DUK__EMIT_1(js_ctx, 0x0a);
35895         if (DUK_UNLIKELY(depth == 0)) {
35896                 return;
35897         }
35898
35899         /* To handle deeper indents efficiently, make use of copies we've
35900          * already emitted.  In effect we can emit a sequence of 1, 2, 4,
35901          * 8, etc copies, and then finish the last run.  Byte counters
35902          * avoid multiply with gap_len on every loop.
35903          */
35904
35905         gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap);
35906         gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap);
35907         DUK_ASSERT(gap_len > 0);
35908
35909         need_bytes = gap_len * depth;
35910         p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes);
35911         p_start = p;
35912
35913         duk_memcpy((void *) p, (const void *) gap_data, (size_t) gap_len);
35914         p += gap_len;
35915         avail_bytes = gap_len;
35916         DUK_ASSERT(need_bytes >= gap_len);
35917         need_bytes -= gap_len;
35918
35919         while (need_bytes >= avail_bytes) {
35920                 duk_memcpy((void *) p, (const void *) p_start, (size_t) avail_bytes);
35921                 p += avail_bytes;
35922                 need_bytes -= avail_bytes;
35923                 avail_bytes <<= 1;
35924         }
35925
35926         DUK_ASSERT(need_bytes < avail_bytes);  /* need_bytes may be zero */
35927         duk_memcpy((void *) p, (const void *) p_start, (size_t) need_bytes);
35928         p += need_bytes;
35929         /*avail_bytes += need_bytes*/
35930
35931         DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p);
35932 }
35933 #endif  /* DUK_USE_PREFER_SIZE */
35934
35935 /* Shared entry handling for object/array serialization. */
35936 DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
35937         duk_hthread *thr = js_ctx->thr;
35938         duk_hobject *h_target;
35939         duk_uint_fast32_t i, n;
35940
35941         *entry_top = duk_get_top(thr);
35942
35943         duk_require_stack(thr, DUK_JSON_ENC_REQSTACK);
35944
35945         /* Loop check using a hybrid approach: a fixed-size visited[] array
35946          * with overflow in a loop check object.
35947          */
35948
35949         h_target = duk_known_hobject(thr, -1);  /* object or array */
35950
35951         n = js_ctx->recursion_depth;
35952         if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
35953                 n = DUK_JSON_ENC_LOOPARRAY;
35954         }
35955         for (i = 0; i < n; i++) {
35956                 if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
35957                         DUK_DD(DUK_DDPRINT("slow path loop detect"));
35958                         DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
35959                         DUK_WO_NORETURN(return;);
35960                 }
35961         }
35962         if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
35963                 js_ctx->visiting[js_ctx->recursion_depth] = h_target;
35964         } else {
35965                 duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
35966                 duk_dup_top(thr);  /* -> [ ... voidp voidp ] */
35967                 if (duk_has_prop(thr, js_ctx->idx_loop)) {
35968                         DUK_ERROR_TYPE(thr, DUK_STR_CYCLIC_INPUT);
35969                         DUK_WO_NORETURN(return;);
35970                 }
35971                 duk_push_true(thr);  /* -> [ ... voidp true ] */
35972                 duk_put_prop(thr, js_ctx->idx_loop);  /* -> [ ... ] */
35973         }
35974
35975         /* C recursion check. */
35976
35977         DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0);  /* unsigned */
35978         DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
35979         if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
35980                 DUK_ERROR_RANGE(thr, DUK_STR_JSONENC_RECLIMIT);
35981                 DUK_WO_NORETURN(return;);
35982         }
35983         js_ctx->recursion_depth++;
35984
35985         DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
35986                              (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
35987 }
35988
35989 /* Shared exit handling for object/array serialization. */
35990 DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
35991         duk_hthread *thr = js_ctx->thr;
35992         duk_hobject *h_target;
35993
35994         /* C recursion check. */
35995
35996         DUK_ASSERT(js_ctx->recursion_depth > 0);
35997         DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
35998         js_ctx->recursion_depth--;
35999
36000         /* Loop check. */
36001
36002         h_target = duk_known_hobject(thr, *entry_top - 1);  /* original target at entry_top - 1 */
36003
36004         if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
36005                 /* Previous entry was inside visited[], nothing to do. */
36006         } else {
36007                 duk_push_sprintf(thr, DUK_STR_FMT_PTR, (void *) h_target);
36008                 duk_del_prop(thr, js_ctx->idx_loop);  /* -> [ ... ] */
36009         }
36010
36011         /* Restore stack top after unbalanced code paths. */
36012         duk_set_top(thr, *entry_top);
36013
36014         DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
36015                              (long) duk_get_top(thr), (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop)));
36016 }
36017
36018 /* The JO(value) operation: encode object.
36019  *
36020  * Stack policy: [ object ] -> [ object ].
36021  */
36022 DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
36023         duk_hthread *thr = js_ctx->thr;
36024         duk_hstring *h_key;
36025         duk_idx_t entry_top;
36026         duk_idx_t idx_obj;
36027         duk_idx_t idx_keys;
36028         duk_bool_t emitted;
36029         duk_uarridx_t arr_len, i;
36030         duk_size_t prev_size;
36031
36032         DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(thr, -1)));
36033
36034         duk__enc_objarr_entry(js_ctx, &entry_top);
36035
36036         idx_obj = entry_top - 1;
36037
36038         if (js_ctx->idx_proplist >= 0) {
36039                 idx_keys = js_ctx->idx_proplist;
36040         } else {
36041                 /* XXX: would be nice to enumerate an object at specified index */
36042                 duk_dup(thr, idx_obj);
36043                 (void) duk_hobject_get_enumerated_keys(thr, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);  /* [ ... target ] -> [ ... target keys ] */
36044                 idx_keys = duk_require_normalize_index(thr, -1);
36045                 /* leave stack unbalanced on purpose */
36046         }
36047
36048         DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
36049                              (long) idx_keys, (duk_tval *) duk_get_tval(thr, idx_keys)));
36050
36051         /* Steps 8-10 have been merged to avoid a "partial" variable. */
36052
36053         DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
36054
36055         /* XXX: keys is an internal object with all keys to be processed
36056          * in its (gapless) array part.  Because nobody can touch the keys
36057          * object, we could iterate its array part directly (keeping in mind
36058          * that it can be reallocated).
36059          */
36060
36061         arr_len = (duk_uarridx_t) duk_get_length(thr, idx_keys);
36062         emitted = 0;
36063         for (i = 0; i < arr_len; i++) {
36064                 duk_get_prop_index(thr, idx_keys, i);  /* -> [ ... key ] */
36065
36066                 DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
36067                                      (duk_tval *) duk_get_tval(thr, idx_obj),
36068                                      (duk_tval *) duk_get_tval(thr, -1)));
36069
36070                 h_key = duk_known_hstring(thr, -1);
36071                 DUK_ASSERT(h_key != NULL);
36072                 DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key));  /* proplist filtering; enum options */
36073
36074                 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
36075                 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
36076                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
36077                         duk__enc_key_autoquote(js_ctx, h_key);
36078                         DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
36079                 } else {
36080                         duk__enc_key_autoquote(js_ctx, h_key);
36081                         DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
36082                 }
36083
36084                 /* [ ... key ] */
36085
36086                 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_obj) == 0)) {
36087                         /* Value would yield 'undefined', so skip key altogether.
36088                          * Side effects have already happened.
36089                          */
36090                         DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
36091                 } else {
36092                         DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
36093                         emitted = 1;
36094                 }
36095
36096                 /* [ ... ] */
36097         }
36098
36099         if (emitted) {
36100                 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
36101                 DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
36102                 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
36103                         DUK_ASSERT(js_ctx->recursion_depth >= 1);
36104                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
36105                 }
36106         }
36107         DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
36108
36109         duk__enc_objarr_exit(js_ctx, &entry_top);
36110
36111         DUK_ASSERT_TOP(thr, entry_top);
36112 }
36113
36114 /* The JA(value) operation: encode array.
36115  *
36116  * Stack policy: [ array ] -> [ array ].
36117  */
36118 DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
36119         duk_hthread *thr = js_ctx->thr;
36120         duk_idx_t entry_top;
36121         duk_idx_t idx_arr;
36122         duk_bool_t emitted;
36123         duk_uarridx_t i, arr_len;
36124
36125         DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
36126                              (duk_tval *) duk_get_tval(thr, -1)));
36127
36128         duk__enc_objarr_entry(js_ctx, &entry_top);
36129
36130         idx_arr = entry_top - 1;
36131
36132         /* Steps 8-10 have been merged to avoid a "partial" variable. */
36133
36134         DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
36135
36136         arr_len = (duk_uarridx_t) duk_get_length(thr, idx_arr);
36137         emitted = 0;
36138         for (i = 0; i < arr_len; i++) {
36139                 DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
36140                                      (duk_tval *) duk_get_tval(thr, idx_arr),
36141                                      (long) i, (long) arr_len));
36142
36143                 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
36144                         DUK_ASSERT(js_ctx->recursion_depth >= 1);
36145                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
36146                 }
36147
36148                 (void) duk_push_uint_to_hstring(thr, (duk_uint_t) i);  /* -> [ ... key ] */
36149
36150                 /* [ ... key ] */
36151
36152                 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_arr) == 0)) {
36153                         /* Value would normally be omitted, replace with 'null'. */
36154                         DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
36155                 } else {
36156                         ;
36157                 }
36158
36159                 /* [ ... ] */
36160
36161                 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
36162                 emitted = 1;
36163         }
36164
36165         if (emitted) {
36166                 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
36167                 DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
36168                 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
36169                         DUK_ASSERT(js_ctx->recursion_depth >= 1);
36170                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
36171                 }
36172         }
36173         DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
36174
36175         duk__enc_objarr_exit(js_ctx, &entry_top);
36176
36177         DUK_ASSERT_TOP(thr, entry_top);
36178 }
36179
36180 /* The Str(key, holder) operation.
36181  *
36182  * Stack policy: [ ... key ] -> [ ... ]
36183  */
36184 DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
36185         duk_hthread *thr = js_ctx->thr;
36186         duk_tval *tv;
36187         duk_tval *tv_holder;
36188         duk_tval *tv_key;
36189         duk_small_int_t c;
36190
36191         DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
36192                              (long) idx_holder, (duk_tval *) duk_get_tval(thr, idx_holder),
36193                              (duk_tval *) duk_get_tval(thr, -1)));
36194
36195         tv_holder = DUK_GET_TVAL_POSIDX(thr, idx_holder);
36196         DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
36197         tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
36198         DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
36199         DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key)));  /* Caller responsible. */
36200         (void) duk_hobject_getprop(thr, tv_holder, tv_key);
36201
36202         /* -> [ ... key val ] */
36203
36204         DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
36205
36206         /* Standard JSON checks for .toJSON() only for actual objects; for
36207          * example, setting Number.prototype.toJSON and then serializing a
36208          * number won't invoke the .toJSON() method.  However, lightfuncs and
36209          * plain buffers mimic objects so we check for their .toJSON() method.
36210          */
36211         if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
36212                                          DUK_TYPE_MASK_LIGHTFUNC |
36213                                          DUK_TYPE_MASK_BUFFER)) {
36214                 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_TO_JSON);
36215                 if (duk_is_callable(thr, -1)) {  /* toJSON() can also be a lightfunc */
36216                         DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
36217                         /* XXX: duk_dup_unvalidated(thr, -2) etc. */
36218                         duk_dup_m2(thr);          /* -> [ ... key val toJSON val ] */
36219                         duk_dup_m4(thr);          /* -> [ ... key val toJSON val key ] */
36220                         duk_call_method(thr, 1);  /* -> [ ... key val val' ] */
36221                         duk_remove_m2(thr);       /* -> [ ... key val' ] */
36222                 } else {
36223                         duk_pop(thr);             /* -> [ ... key val ] */
36224                 }
36225         }
36226
36227         /* [ ... key val ] */
36228
36229         DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
36230
36231         if (js_ctx->h_replacer) {
36232                 /* XXX: Here a "slice copy" would be useful. */
36233                 DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
36234                 duk_push_hobject(thr, js_ctx->h_replacer);  /* -> [ ... key val replacer ] */
36235                 duk_dup(thr, idx_holder);                   /* -> [ ... key val replacer holder ] */
36236                 duk_dup_m4(thr);                            /* -> [ ... key val replacer holder key ] */
36237                 duk_dup_m4(thr);                            /* -> [ ... key val replacer holder key val ] */
36238                 duk_call_method(thr, 2);                    /* -> [ ... key val val' ] */
36239                 duk_remove_m2(thr);                         /* -> [ ... key val' ] */
36240         }
36241
36242         /* [ ... key val ] */
36243
36244         DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
36245
36246         tv = DUK_GET_TVAL_NEGIDX(thr, -1);
36247         if (DUK_TVAL_IS_OBJECT(tv)) {
36248                 duk_hobject *h;
36249
36250                 h = DUK_TVAL_GET_OBJECT(tv);
36251                 DUK_ASSERT(h != NULL);
36252
36253 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
36254 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36255                 if (DUK_HOBJECT_IS_BUFOBJ(h) &&
36256                     js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE)) {
36257                         /* With JX/JC a bufferobject gets serialized specially. */
36258                         duk_hbufobj *h_bufobj;
36259                         h_bufobj = (duk_hbufobj *) h;
36260                         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
36261                         duk__enc_bufobj(js_ctx, h_bufobj);
36262                         goto pop2_emitted;
36263                 }
36264                 /* Otherwise bufferobjects get serialized as normal objects. */
36265 #endif  /* JX || JC */
36266 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
36267                 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
36268                 switch (c) {
36269                 case DUK_HOBJECT_CLASS_NUMBER: {
36270                         DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
36271                         duk_to_number_m1(thr);
36272                         /* The coercion potentially invokes user .valueOf() and .toString()
36273                          * but can't result in a function value because ToPrimitive() would
36274                          * reject such a result: test-dev-json-stringify-coercion-1.js.
36275                          */
36276                         DUK_ASSERT(!duk_is_callable(thr, -1));
36277                         break;
36278                 }
36279                 case DUK_HOBJECT_CLASS_STRING: {
36280                         DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
36281                         duk_to_string(thr, -1);
36282                         /* Same coercion behavior as for Number. */
36283                         DUK_ASSERT(!duk_is_callable(thr, -1));
36284                         break;
36285                 }
36286 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36287                 case DUK_HOBJECT_CLASS_POINTER:
36288 #endif
36289                 case DUK_HOBJECT_CLASS_BOOLEAN: {
36290                         DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
36291                         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
36292                         duk_remove_m2(thr);
36293                         break;
36294                 }
36295                 default: {
36296                         /* Normal object which doesn't get automatically coerced to a
36297                          * primitive value.  Functions are checked for specially.  The
36298                          * primitive value coercions for Number, String, Pointer, and
36299                          * Boolean can't result in functions so suffices to check here.
36300                          * Symbol objects are handled like plain objects (their primitive
36301                          * value is NOT looked up like for e.g. String objects).
36302                          */
36303                         DUK_ASSERT(h != NULL);
36304                         if (DUK_HOBJECT_IS_CALLABLE(h)) {
36305 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36306                                 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
36307                                                      DUK_JSON_FLAG_EXT_COMPATIBLE)) {
36308                                         /* We only get here when doing non-standard JSON encoding */
36309                                         DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
36310                                         DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
36311                                         DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
36312                                         goto pop2_emitted;
36313                                 } else {
36314                                         DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
36315                                         goto pop2_undef;
36316                                 }
36317 #else  /* DUK_USE_JX || DUK_USE_JC */
36318                                 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
36319                                 goto pop2_undef;
36320 #endif  /* DUK_USE_JX || DUK_USE_JC */
36321                         }
36322                 }
36323                 }  /* end switch */
36324         }
36325
36326         /* [ ... key val ] */
36327
36328         DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(thr, -1)));
36329
36330         if (duk_check_type_mask(thr, -1, js_ctx->mask_for_undefined)) {
36331                 /* will result in undefined */
36332                 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
36333                 goto pop2_undef;
36334         }
36335         tv = DUK_GET_TVAL_NEGIDX(thr, -1);
36336
36337         switch (DUK_TVAL_GET_TAG(tv)) {
36338 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36339         /* When JX/JC not in use, the type mask above will avoid this case if needed. */
36340         case DUK_TAG_UNDEFINED: {
36341                 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
36342                 break;
36343         }
36344 #endif
36345         case DUK_TAG_NULL: {
36346                 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
36347                 break;
36348         }
36349         case DUK_TAG_BOOLEAN: {
36350                 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
36351                                  DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
36352                 break;
36353         }
36354 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36355         /* When JX/JC not in use, the type mask above will avoid this case if needed. */
36356         case DUK_TAG_POINTER: {
36357                 duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
36358                 break;
36359         }
36360 #endif  /* DUK_USE_JX || DUK_USE_JC */
36361         case DUK_TAG_STRING: {
36362                 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
36363                 DUK_ASSERT(h != NULL);
36364                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
36365                         goto pop2_undef;
36366                 }
36367                 duk__enc_quote_string(js_ctx, h);
36368                 break;
36369         }
36370         case DUK_TAG_OBJECT: {
36371                 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
36372                 DUK_ASSERT(h != NULL);
36373
36374                 /* Function values are handled completely above (including
36375                  * coercion results):
36376                  */
36377                 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h));
36378
36379                 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
36380                         duk__enc_array(js_ctx);
36381                 } else {
36382                         duk__enc_object(js_ctx);
36383                 }
36384                 break;
36385         }
36386         /* Because plain buffers mimics Uint8Array, they have enumerable
36387          * index properties [0,byteLength[.  Because JSON only serializes
36388          * enumerable own properties, no properties can be serialized for
36389          * plain buffers (all virtual properties are non-enumerable).  However,
36390          * there may be a .toJSON() method which was already handled above.
36391          */
36392         case DUK_TAG_BUFFER: {
36393 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36394                 if (js_ctx->flag_ext_custom_or_compatible) {
36395                         duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
36396                         break;
36397                 }
36398 #endif
36399
36400                 /* Could implement a fastpath, but the fast path would need
36401                  * to handle realloc side effects correctly.
36402                  */
36403                 duk_to_object(thr, -1);
36404                 duk__enc_object(js_ctx);
36405                 break;
36406         }
36407         case DUK_TAG_LIGHTFUNC: {
36408 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36409                 /* We only get here when doing non-standard JSON encoding */
36410                 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
36411                 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
36412 #else
36413                 /* Standard JSON omits functions */
36414                 DUK_UNREACHABLE();
36415 #endif
36416                 break;
36417         }
36418 #if defined(DUK_USE_FASTINT)
36419         case DUK_TAG_FASTINT:
36420                 /* Number serialization has a significant impact relative to
36421                  * other fast path code, so careful fast path for fastints.
36422                  */
36423                 duk__enc_fastint_tval(js_ctx, tv);
36424                 break;
36425 #endif
36426         default: {
36427                 /* number */
36428                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
36429                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
36430                 /* XXX: A fast path for usual integers would be useful when
36431                  * fastint support is not enabled.
36432                  */
36433                 duk__enc_double(js_ctx);
36434                 break;
36435         }
36436         }
36437
36438 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36439  pop2_emitted:
36440 #endif
36441         duk_pop_2(thr); /* [ ... key val ] -> [ ... ] */
36442         return 1;  /* emitted */
36443
36444  pop2_undef:
36445         duk_pop_2(thr);  /* [ ... key val ] -> [ ... ] */
36446         return 0;  /* not emitted */
36447 }
36448
36449 /* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
36450 DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
36451         duk_small_int_t c;
36452
36453         /* XXX: some kind of external internal type checker?
36454          * - type mask; symbol flag; class mask
36455          */
36456         DUK_ASSERT(tv != NULL);
36457         if (DUK_TVAL_IS_STRING(tv)) {
36458                 duk_hstring *h;
36459                 h = DUK_TVAL_GET_STRING(tv);
36460                 DUK_ASSERT(h != NULL);
36461                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
36462                         return 0;
36463                 }
36464                 return 1;
36465         } else if (DUK_TVAL_IS_NUMBER(tv)) {
36466                 return 1;
36467         } else if (DUK_TVAL_IS_OBJECT(tv)) {
36468                 duk_hobject *h;
36469                 h = DUK_TVAL_GET_OBJECT(tv);
36470                 DUK_ASSERT(h != NULL);
36471                 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
36472                 if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) {
36473                         return 1;
36474                 }
36475         }
36476
36477         return 0;
36478 }
36479
36480 /*
36481  *  JSON.stringify() fast path
36482  *
36483  *  Otherwise supports full JSON, JX, and JC features, but bails out on any
36484  *  possible side effect which might change the value being serialized.  The
36485  *  fast path can take advantage of the fact that the value being serialized
36486  *  is unchanged so that we can walk directly through property tables etc.
36487  */
36488
36489 #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
36490 DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
36491         duk_uint_fast32_t i, n;
36492
36493         DUK_DDD(DUK_DDDPRINT("stringify fast: %!T", tv));
36494
36495         DUK_ASSERT(js_ctx != NULL);
36496         DUK_ASSERT(js_ctx->thr != NULL);
36497
36498 #if 0 /* disabled for now */
36499  restart_match:
36500 #endif
36501
36502         DUK_ASSERT(tv != NULL);
36503
36504         switch (DUK_TVAL_GET_TAG(tv)) {
36505         case DUK_TAG_UNDEFINED: {
36506 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36507                 if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) {
36508                         DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
36509                         break;
36510                 } else {
36511                         goto emit_undefined;
36512                 }
36513 #else
36514                 goto emit_undefined;
36515 #endif
36516         }
36517         case DUK_TAG_NULL: {
36518                 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
36519                 break;
36520         }
36521         case DUK_TAG_BOOLEAN: {
36522                 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
36523                                  DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
36524                 break;
36525         }
36526         case DUK_TAG_STRING: {
36527                 duk_hstring *h;
36528                 h = DUK_TVAL_GET_STRING(tv);
36529                 DUK_ASSERT(h != NULL);
36530                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
36531                         goto emit_undefined;
36532                 }
36533                 duk__enc_quote_string(js_ctx, h);
36534                 break;
36535         }
36536         case DUK_TAG_OBJECT: {
36537                 duk_hobject *obj;
36538                 duk_tval *tv_val;
36539                 duk_bool_t emitted = 0;
36540                 duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
36541                              c_func, c_bufobj, c_object, c_abort;
36542
36543                 /* For objects JSON.stringify() only looks for own, enumerable
36544                  * properties which is nice for the fast path here.
36545                  *
36546                  * For arrays JSON.stringify() uses [[Get]] so it will actually
36547                  * inherit properties during serialization!  This fast path
36548                  * supports gappy arrays as long as there's no actual inherited
36549                  * property (which might be a getter etc).
36550                  *
36551                  * Since recursion only happens for objects, we can have both
36552                  * recursion and loop checks here.  We use a simple, depth-limited
36553                  * loop check in the fast path because the object-based tracking
36554                  * is very slow (when tested, it accounted for 50% of fast path
36555                  * execution time for input data with a lot of small objects!).
36556                  */
36557
36558                 /* XXX: for real world code, could just ignore array inheritance
36559                  * and only look at array own properties.
36560                  */
36561
36562                 /* We rely on a few object flag / class number relationships here,
36563                  * assert for them.
36564                  */
36565
36566                 obj = DUK_TVAL_GET_OBJECT(tv);
36567                 DUK_ASSERT(obj != NULL);
36568                 DUK_ASSERT_HOBJECT_VALID(obj);
36569
36570                 /* Once recursion depth is increased, exit path must decrease
36571                  * it (though it's OK to abort the fast path).
36572                  */
36573
36574                 DUK_ASSERT_DISABLE(js_ctx->recursion_depth >= 0);  /* unsigned */
36575                 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
36576                 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
36577                         DUK_DD(DUK_DDPRINT("fast path recursion limit"));
36578                         DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT);
36579                         DUK_WO_NORETURN(return 0;);
36580                 }
36581
36582                 for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) {
36583                         if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) {
36584                                 DUK_DD(DUK_DDPRINT("fast path loop detect"));
36585                                 DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT);
36586                                 DUK_WO_NORETURN(return 0;);
36587                         }
36588                 }
36589
36590                 /* Guaranteed by recursion_limit setup so we don't have to
36591                  * check twice.
36592                  */
36593                 DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY);
36594                 js_ctx->visiting[js_ctx->recursion_depth] = obj;
36595                 js_ctx->recursion_depth++;
36596
36597                 /* If object has a .toJSON() property, we can't be certain
36598                  * that it wouldn't mutate any value arbitrarily, so bail
36599                  * out of the fast path.
36600                  *
36601                  * If an object is a Proxy we also can't avoid side effects
36602                  * so abandon.
36603                  */
36604                 /* XXX: non-callable .toJSON() doesn't need to cause an abort
36605                  * but does at the moment, probably not worth fixing.
36606                  */
36607                 if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
36608                     DUK_HOBJECT_IS_PROXY(obj)) {
36609                         DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
36610                         goto abort_fastpath;
36611                 }
36612
36613                 /* We could use a switch-case for the class number but it turns out
36614                  * a small if-else ladder on class masks is better.  The if-ladder
36615                  * should be in order of relevancy.
36616                  */
36617
36618                 /* XXX: move masks to js_ctx? they don't change during one
36619                  * fast path invocation.
36620                  */
36621                 DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31);
36622 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36623                 if (js_ctx->flag_ext_custom_or_compatible) {
36624                         c_all = DUK_HOBJECT_CMASK_ALL;
36625                         c_array = DUK_HOBJECT_CMASK_ARRAY;
36626                         c_unbox = DUK_HOBJECT_CMASK_NUMBER |
36627                                   DUK_HOBJECT_CMASK_STRING |
36628                                   DUK_HOBJECT_CMASK_BOOLEAN |
36629                                   DUK_HOBJECT_CMASK_POINTER;  /* Symbols are not unboxed. */
36630                         c_func = DUK_HOBJECT_CMASK_FUNCTION;
36631                         c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
36632                         c_undef = 0;
36633                         c_abort = 0;
36634                         c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
36635                 }
36636                 else
36637 #endif
36638                 {
36639                         c_all = DUK_HOBJECT_CMASK_ALL;
36640                         c_array = DUK_HOBJECT_CMASK_ARRAY;
36641                         c_unbox = DUK_HOBJECT_CMASK_NUMBER |
36642                                   DUK_HOBJECT_CMASK_STRING |
36643                                   DUK_HOBJECT_CMASK_BOOLEAN;  /* Symbols are not unboxed. */
36644                         c_func = 0;
36645                         c_bufobj = 0;
36646                         c_undef = DUK_HOBJECT_CMASK_FUNCTION |
36647                                   DUK_HOBJECT_CMASK_POINTER;
36648                         /* As the fast path doesn't currently properly support
36649                          * duk_hbufobj virtual properties, abort fast path if
36650                          * we encounter them in plain JSON mode.
36651                          */
36652                         c_abort = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
36653                         c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
36654                 }
36655
36656                 c_bit = (duk_uint32_t) DUK_HOBJECT_GET_CLASS_MASK(obj);
36657                 if (c_bit & c_object) {
36658                         /* All other object types. */
36659                         DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
36660
36661                         /* A non-Array object should not have an array part in practice.
36662                          * But since it is supported internally (and perhaps used at some
36663                          * point), check and abandon if that's the case.
36664                          */
36665                         if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
36666                                 DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path"));
36667                                 goto abort_fastpath;
36668                         }
36669
36670                         for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) {
36671                                 duk_hstring *k;
36672                                 duk_size_t prev_size;
36673
36674                                 k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i);
36675                                 if (!k) {
36676                                         continue;
36677                                 }
36678                                 if (DUK_HSTRING_HAS_ARRIDX(k)) {
36679                                         /* If an object has array index keys we would need
36680                                          * to sort them into the ES2015 enumeration order to
36681                                          * be consistent with the slow path.  Abort the fast
36682                                          * path and handle in the slow path for now.
36683                                          */
36684                                         DUK_DD(DUK_DDPRINT("property key is an array index, abort fast path"));
36685                                         goto abort_fastpath;
36686                                 }
36687                                 if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) {
36688                                         continue;
36689                                 }
36690                                 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) {
36691                                         /* Getter might have arbitrary side effects,
36692                                          * so bail out.
36693                                          */
36694                                         DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path"));
36695                                         goto abort_fastpath;
36696                                 }
36697                                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) {
36698                                         continue;
36699                                 }
36700
36701                                 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i);
36702
36703                                 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
36704                                 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
36705                                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
36706                                         duk__enc_key_autoquote(js_ctx, k);
36707                                         DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
36708                                 } else {
36709                                         duk__enc_key_autoquote(js_ctx, k);
36710                                         DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
36711                                 }
36712
36713                                 if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
36714                                         DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon"));
36715                                         DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
36716                                 } else {
36717                                         DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
36718                                         emitted = 1;
36719                                 }
36720                         }
36721
36722                         /* If any non-Array value had enumerable virtual own
36723                          * properties, they should be serialized here (actually,
36724                          * before the explicit properties).  Standard types don't.
36725                          */
36726
36727                         if (emitted) {
36728                                 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
36729                                 DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
36730                                 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
36731                                         DUK_ASSERT(js_ctx->recursion_depth >= 1);
36732                                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
36733                                 }
36734                         }
36735                         DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
36736                 } else if (c_bit & c_array) {
36737                         duk_uint_fast32_t arr_len;
36738                         duk_uint_fast32_t asize;
36739
36740                         DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
36741
36742                         /* Assume arrays are dense in the fast path. */
36743                         if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
36744                                 DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path"));
36745                                 goto abort_fastpath;
36746                         }
36747
36748                         arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length;
36749                         asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
36750                         /* Array part may be larger than 'length'; if so, iterate
36751                          * only up to array 'length'.  Array part may also be smaller
36752                          * than 'length' in some cases.
36753                          */
36754                         for (i = 0; i < arr_len; i++) {
36755                                 duk_tval *tv_arrval;
36756                                 duk_hstring *h_tmp;
36757                                 duk_bool_t has_inherited;
36758
36759                                 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
36760                                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
36761                                 }
36762
36763                                 if (DUK_LIKELY(i < asize)) {
36764                                         tv_arrval = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
36765                                         if (DUK_LIKELY(!DUK_TVAL_IS_UNUSED(tv_arrval))) {
36766                                                 /* Expected case: element is present. */
36767                                                 if (duk__json_stringify_fast_value(js_ctx, tv_arrval) == 0) {
36768                                                         DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
36769                                                 }
36770                                                 goto elem_done;
36771                                         }
36772                                 }
36773
36774                                 /* Gap in array; check for inherited property,
36775                                  * bail out if one exists.  This should be enough
36776                                  * to support gappy arrays for all practical code.
36777                                  */
36778
36779                                 h_tmp = duk_push_uint_to_hstring(js_ctx->thr, (duk_uint_t) i);
36780                                 has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
36781                                 duk_pop(js_ctx->thr);
36782                                 if (has_inherited) {
36783                                         DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
36784                                         goto abort_fastpath;
36785                                 }
36786
36787                                 /* Ordinary gap, undefined encodes to 'null' in
36788                                  * standard JSON, but JX/JC use their form for
36789                                  * undefined to better preserve the typing.
36790                                  */
36791                                 DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
36792 #if defined(DUK_USE_JX)
36793                                 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
36794 #else
36795                                 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
36796 #endif
36797                                 /* fall through */
36798
36799                          elem_done:
36800                                 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
36801                                 emitted = 1;
36802                         }
36803
36804                         if (emitted) {
36805                                 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
36806                                 DUK__UNEMIT_1(js_ctx);  /* eat trailing comma */
36807                                 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
36808                                         DUK_ASSERT(js_ctx->recursion_depth >= 1);
36809                                         duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1U);
36810                                 }
36811                         }
36812                         DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
36813                 } else if (c_bit & c_unbox) {
36814                         /* Certain boxed types are required to go through
36815                          * automatic unboxing.  Rely on internal value being
36816                          * sane (to avoid infinite recursion).
36817                          */
36818                         DUK_ASSERT((c_bit & DUK_HOBJECT_CMASK_SYMBOL) == 0);  /* Symbols are not unboxed. */
36819
36820 #if 1
36821                         /* The code below is incorrect if .toString() or .valueOf() have
36822                          * have been overridden.  The correct approach would be to look up
36823                          * the method(s) and if they resolve to the built-in function we
36824                          * can safely bypass it and look up the internal value directly.
36825                          * Unimplemented for now, abort fast path for boxed values.
36826                          */
36827                         goto abort_fastpath;
36828 #else  /* disabled */
36829                         /* Disabled until fixed, see above. */
36830                         duk_tval *tv_internal;
36831
36832                         DUK_DD(DUK_DDPRINT("auto unboxing in fast path"));
36833
36834                         tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj);
36835                         DUK_ASSERT(tv_internal != NULL);
36836                         DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) ||
36837                                    DUK_TVAL_IS_NUMBER(tv_internal) ||
36838                                    DUK_TVAL_IS_BOOLEAN(tv_internal) ||
36839                                    DUK_TVAL_IS_POINTER(tv_internal));
36840
36841                         tv = tv_internal;
36842                         DUK_ASSERT(js_ctx->recursion_depth > 0);
36843                         js_ctx->recursion_depth--;  /* required to keep recursion depth correct */
36844                         goto restart_match;
36845 #endif  /* disabled */
36846 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36847                 } else if (c_bit & c_func) {
36848                         DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
36849 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
36850                 } else if (c_bit & c_bufobj) {
36851                         duk__enc_bufobj(js_ctx, (duk_hbufobj *) obj);
36852 #endif
36853 #endif
36854                 } else if (c_bit & c_abort) {
36855                         DUK_DD(DUK_DDPRINT("abort fast path for unsupported type"));
36856                         goto abort_fastpath;
36857                 } else {
36858                         DUK_ASSERT((c_bit & c_undef) != 0);
36859
36860                         /* Must decrease recursion depth before returning. */
36861                         DUK_ASSERT(js_ctx->recursion_depth > 0);
36862                         DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
36863                         js_ctx->recursion_depth--;
36864                         goto emit_undefined;
36865                 }
36866
36867                 DUK_ASSERT(js_ctx->recursion_depth > 0);
36868                 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
36869                 js_ctx->recursion_depth--;
36870                 break;
36871         }
36872         case DUK_TAG_BUFFER: {
36873                 /* Plain buffers are treated like Uint8Arrays: they have
36874                  * enumerable indices.  Other virtual properties are not
36875                  * enumerable, and inherited properties are not serialized.
36876                  * However, there can be a replacer (not relevant here) or
36877                  * a .toJSON() method (which we need to check for explicitly).
36878                  */
36879
36880 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
36881                 if (duk_hobject_hasprop_raw(js_ctx->thr,
36882                                             js_ctx->thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE],
36883                                             DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr))) {
36884                         DUK_DD(DUK_DDPRINT("value is a plain buffer and there's an inherited .toJSON, abort fast path"));
36885                         goto abort_fastpath;
36886                 }
36887 #endif
36888
36889 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36890                 if (js_ctx->flag_ext_custom_or_compatible) {
36891                         duk__enc_buffer_jx_jc(js_ctx, DUK_TVAL_GET_BUFFER(tv));
36892                         break;
36893                 }
36894 #endif
36895
36896                 /* Plain buffers mimic Uint8Arrays, and have enumerable index
36897                  * properties.
36898                  */
36899                 duk__enc_buffer_json_fastpath(js_ctx, DUK_TVAL_GET_BUFFER(tv));
36900                 break;
36901         }
36902         case DUK_TAG_POINTER: {
36903 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
36904                 if (js_ctx->flag_ext_custom_or_compatible) {
36905                         duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
36906                         break;
36907                 } else {
36908                         goto emit_undefined;
36909                 }
36910 #else
36911                 goto emit_undefined;
36912 #endif
36913         }
36914         case DUK_TAG_LIGHTFUNC: {
36915                 /* A lightfunc might also inherit a .toJSON() so just bail out. */
36916                 /* XXX: Could just lookup .toJSON() and continue in fast path,
36917                  * as it would almost never be defined.
36918                  */
36919                 DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path"));
36920                 goto abort_fastpath;
36921         }
36922 #if defined(DUK_USE_FASTINT)
36923         case DUK_TAG_FASTINT: {
36924                 /* Number serialization has a significant impact relative to
36925                  * other fast path code, so careful fast path for fastints.
36926                  */
36927                 duk__enc_fastint_tval(js_ctx, tv);
36928                 break;
36929         }
36930 #endif
36931         default: {
36932                 /* XXX: A fast path for usual integers would be useful when
36933                  * fastint support is not enabled.
36934                  */
36935                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
36936                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
36937
36938                 /* XXX: Stack discipline is annoying, could be changed in numconv. */
36939                 duk_push_tval(js_ctx->thr, tv);
36940                 duk__enc_double(js_ctx);
36941                 duk_pop(js_ctx->thr);
36942
36943 #if 0
36944                 /* Could also rely on native sprintf(), but it will handle
36945                  * values like NaN, Infinity, -0, exponent notation etc in
36946                  * a JSON-incompatible way.
36947                  */
36948                 duk_double_t d;
36949                 char buf[64];
36950
36951                 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
36952                 d = DUK_TVAL_GET_DOUBLE(tv);
36953                 DUK_SPRINTF(buf, "%lg", d);
36954                 DUK__EMIT_CSTR(js_ctx, buf);
36955 #endif
36956         }
36957         }
36958         return 1;  /* not undefined */
36959
36960  emit_undefined:
36961         return 0;  /* value was undefined/unsupported */
36962
36963  abort_fastpath:
36964         /* Error message doesn't matter: the error is ignored anyway. */
36965         DUK_DD(DUK_DDPRINT("aborting fast path"));
36966         DUK_ERROR_INTERNAL(js_ctx->thr);
36967         DUK_WO_NORETURN(return 0;);
36968 }
36969
36970 DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_hthread *thr, void *udata) {
36971         duk_json_enc_ctx *js_ctx;
36972         duk_tval *tv;
36973
36974         DUK_ASSERT(thr != NULL);
36975         DUK_ASSERT(udata != NULL);
36976
36977         js_ctx = (duk_json_enc_ctx *) udata;
36978         DUK_ASSERT(js_ctx != NULL);
36979
36980         tv = DUK_GET_TVAL_NEGIDX(thr, -1);
36981         if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
36982                 DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
36983                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);  /* Error message is ignored, so doesn't matter. */
36984         }
36985
36986         return 0;
36987 }
36988 #endif  /* DUK_USE_JSON_STRINGIFY_FASTPATH */
36989
36990 /*
36991  *  Top level wrappers
36992  */
36993
36994 DUK_INTERNAL
36995 void duk_bi_json_parse_helper(duk_hthread *thr,
36996                               duk_idx_t idx_value,
36997                               duk_idx_t idx_reviver,
36998                               duk_small_uint_t flags) {
36999         duk_json_dec_ctx js_ctx_alloc;
37000         duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
37001         duk_hstring *h_text;
37002 #if defined(DUK_USE_ASSERTIONS)
37003         duk_idx_t entry_top = duk_get_top(thr);
37004 #endif
37005
37006         /* negative top-relative indices not allowed now */
37007         DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
37008         DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
37009
37010         DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
37011                              (duk_tval *) duk_get_tval(thr, idx_value),
37012                              (duk_tval *) duk_get_tval(thr, idx_reviver),
37013                              (unsigned long) flags,
37014                              (long) duk_get_top(thr)));
37015
37016         duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc));
37017         js_ctx->thr = thr;
37018 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
37019         /* nothing now */
37020 #endif
37021         js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT;
37022         DUK_ASSERT(js_ctx->recursion_depth == 0);
37023
37024         /* Flag handling currently assumes that flags are consistent.  This is OK
37025          * because the call sites are now strictly controlled.
37026          */
37027
37028         js_ctx->flags = flags;
37029 #if defined(DUK_USE_JX)
37030         js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
37031 #endif
37032 #if defined(DUK_USE_JC)
37033         js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
37034 #endif
37035 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
37036         js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
37037 #endif
37038
37039         h_text = duk_to_hstring(thr, idx_value);  /* coerce in-place; rejects Symbols */
37040         DUK_ASSERT(h_text != NULL);
37041
37042         /* JSON parsing code is allowed to read [p_start,p_end]: p_end is
37043          * valid and points to the string NUL terminator (which is always
37044          * guaranteed for duk_hstrings.
37045          */
37046         js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
37047         js_ctx->p = js_ctx->p_start;
37048         js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
37049                         DUK_HSTRING_GET_BYTELEN(h_text);
37050         DUK_ASSERT(*(js_ctx->p_end) == 0x00);
37051
37052         duk__dec_value(js_ctx);  /* -> [ ... value ] */
37053
37054         /* Trailing whitespace has been eaten by duk__dec_value(), so if
37055          * we're not at end of input here, it's a SyntaxError.
37056          */
37057
37058         if (js_ctx->p != js_ctx->p_end) {
37059                 duk__dec_syntax_error(js_ctx);
37060         }
37061
37062         if (duk_is_callable(thr, idx_reviver)) {
37063                 DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
37064                                      (duk_tval *) duk_get_tval(thr, idx_reviver)));
37065
37066                 js_ctx->idx_reviver = idx_reviver;
37067
37068                 duk_push_object(thr);
37069                 duk_dup_m2(thr);  /* -> [ ... val root val ] */
37070                 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING);  /* default attrs ok */
37071                 duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING);  /* -> [ ... val root "" ] */
37072
37073                 DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
37074                                      (duk_tval *) duk_get_tval(thr, -2),
37075                                      (duk_tval *) duk_get_tval(thr, -1)));
37076
37077                 duk__dec_reviver_walk(js_ctx);  /* [ ... val root "" ] -> [ ... val val' ] */
37078                 duk_remove_m2(thr);             /* -> [ ... val' ] */
37079         } else {
37080                 DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
37081                                      (duk_tval *) duk_get_tval(thr, idx_reviver)));
37082         }
37083
37084         /* Final result is at stack top. */
37085
37086         DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
37087                              (duk_tval *) duk_get_tval(thr, idx_value),
37088                              (duk_tval *) duk_get_tval(thr, idx_reviver),
37089                              (unsigned long) flags,
37090                              (duk_tval *) duk_get_tval(thr, -1),
37091                              (long) duk_get_top(thr)));
37092
37093         DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
37094 }
37095
37096 DUK_INTERNAL
37097 void duk_bi_json_stringify_helper(duk_hthread *thr,
37098                                   duk_idx_t idx_value,
37099                                   duk_idx_t idx_replacer,
37100                                   duk_idx_t idx_space,
37101                                   duk_small_uint_t flags) {
37102         duk_json_enc_ctx js_ctx_alloc;
37103         duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
37104         duk_hobject *h;
37105         duk_idx_t idx_holder;
37106         duk_idx_t entry_top;
37107
37108         /* negative top-relative indices not allowed now */
37109         DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
37110         DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0);
37111         DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
37112
37113         DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
37114                              (duk_tval *) duk_get_tval(thr, idx_value),
37115                              (duk_tval *) duk_get_tval(thr, idx_replacer),
37116                              (duk_tval *) duk_get_tval(thr, idx_space),
37117                              (unsigned long) flags,
37118                              (long) duk_get_top(thr)));
37119
37120         entry_top = duk_get_top(thr);
37121
37122         /*
37123          *  Context init
37124          */
37125
37126         duk_memzero(&js_ctx_alloc, sizeof(js_ctx_alloc));
37127         js_ctx->thr = thr;
37128 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
37129         js_ctx->h_replacer = NULL;
37130         js_ctx->h_gap = NULL;
37131 #endif
37132         js_ctx->idx_proplist = -1;
37133
37134         /* Flag handling currently assumes that flags are consistent.  This is OK
37135          * because the call sites are now strictly controlled.
37136          */
37137
37138         js_ctx->flags = flags;
37139         js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
37140         js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
37141 #if defined(DUK_USE_JX)
37142         js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
37143 #endif
37144 #if defined(DUK_USE_JC)
37145         js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
37146 #endif
37147 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
37148         js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
37149 #endif
37150
37151         /* The #if defined() clutter here handles the JX/JC enable/disable
37152          * combinations properly.
37153          */
37154 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
37155         js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL;  /* standard JSON; array gaps */
37156 #if defined(DUK_USE_JX)
37157         if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
37158                 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED;
37159                 js_ctx->stridx_custom_nan = DUK_STRIDX_NAN;
37160                 js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY;
37161                 js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY;
37162                 js_ctx->stridx_custom_function =
37163                         (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ?
37164                                 DUK_STRIDX_JSON_EXT_FUNCTION2 :
37165                                 DUK_STRIDX_JSON_EXT_FUNCTION1;
37166         }
37167 #endif  /* DUK_USE_JX */
37168 #if defined(DUK_USE_JX) && defined(DUK_USE_JC)
37169         else
37170 #endif  /* DUK_USE_JX && DUK_USE_JC */
37171 #if defined(DUK_USE_JC)
37172         if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) {
37173                 js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED;
37174                 js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN;
37175                 js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF;
37176                 js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF;
37177                 js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1;
37178         }
37179 #endif  /* DUK_USE_JC */
37180 #endif  /* DUK_USE_JX || DUK_USE_JC */
37181
37182 #if defined(DUK_USE_JX) || defined(DUK_USE_JC)
37183         if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
37184                              DUK_JSON_FLAG_EXT_COMPATIBLE)) {
37185                 DUK_ASSERT(js_ctx->mask_for_undefined == 0);  /* already zero */
37186         }
37187         else
37188 #endif  /* DUK_USE_JX || DUK_USE_JC */
37189         {
37190                 /* Plain buffer is treated like ArrayBuffer and serialized.
37191                  * Lightfuncs are treated like objects, but JSON explicitly
37192                  * skips serializing Function objects so we can just reject
37193                  * lightfuncs here.
37194                  */
37195                 js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
37196                                              DUK_TYPE_MASK_POINTER |
37197                                              DUK_TYPE_MASK_LIGHTFUNC;
37198         }
37199
37200         DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
37201
37202         js_ctx->idx_loop = duk_push_bare_object(thr);
37203         DUK_ASSERT(js_ctx->idx_loop >= 0);
37204
37205         /* [ ... buf loop ] */
37206
37207         /*
37208          *  Process replacer/proplist (2nd argument to JSON.stringify)
37209          */
37210
37211         h = duk_get_hobject(thr, idx_replacer);
37212         if (h != NULL) {
37213                 if (DUK_HOBJECT_IS_CALLABLE(h)) {
37214                         js_ctx->h_replacer = h;
37215                 } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
37216                         /* Here the specification requires correct array index enumeration
37217                          * which is a bit tricky for sparse arrays (it is handled by the
37218                          * enum setup code).  We now enumerate ancestors too, although the
37219                          * specification is not very clear on whether that is required.
37220                          */
37221
37222                         duk_uarridx_t plist_idx = 0;
37223                         duk_small_uint_t enum_flags;
37224
37225                         js_ctx->idx_proplist = duk_push_array(thr);  /* XXX: array internal? */
37226
37227                         enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
37228                                      DUK_ENUM_SORT_ARRAY_INDICES;  /* expensive flag */
37229                         duk_enum(thr, idx_replacer, enum_flags);
37230                         while (duk_next(thr, -1 /*enum_index*/, 1 /*get_value*/)) {
37231                                 /* [ ... proplist enum_obj key val ] */
37232                                 if (duk__enc_allow_into_proplist(duk_get_tval(thr, -1))) {
37233                                         /* XXX: duplicates should be eliminated here */
37234                                         DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
37235                                                              (duk_tval *) duk_get_tval(thr, -2),
37236                                                              (duk_tval *) duk_get_tval(thr, -1)));
37237                                         duk_to_string(thr, -1);  /* extra coercion of strings is OK */
37238                                         duk_put_prop_index(thr, -4, plist_idx);  /* -> [ ... proplist enum_obj key ] */
37239                                         plist_idx++;
37240                                         duk_pop(thr);
37241                                 } else {
37242                                         DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
37243                                                              (duk_tval *) duk_get_tval(thr, -2),
37244                                                              (duk_tval *) duk_get_tval(thr, -1)));
37245                                         duk_pop_2(thr);
37246                                 }
37247                         }
37248                         duk_pop(thr);  /* pop enum */
37249
37250                         /* [ ... proplist ] */
37251                 }
37252         }
37253
37254         /* [ ... buf loop (proplist) ] */
37255
37256         /*
37257          *  Process space (3rd argument to JSON.stringify)
37258          */
37259
37260         h = duk_get_hobject(thr, idx_space);
37261         if (h != NULL) {
37262                 duk_small_uint_t c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
37263                 if (c == DUK_HOBJECT_CLASS_NUMBER) {
37264                         duk_to_number(thr, idx_space);
37265                 } else if (c == DUK_HOBJECT_CLASS_STRING) {
37266                         duk_to_string(thr, idx_space);
37267                 }
37268         }
37269
37270         if (duk_is_number(thr, idx_space)) {
37271                 duk_small_int_t nspace;
37272                 /* spaces[] must be static to allow initializer with old compilers like BCC */
37273                 static const char spaces[10] = {
37274                         DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
37275                         DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
37276                         DUK_ASC_SPACE, DUK_ASC_SPACE
37277                 };  /* XXX: helper */
37278
37279                 /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
37280                 nspace = (duk_small_int_t) duk_to_int_clamped(thr, idx_space, 0 /*minval*/, 10 /*maxval*/);
37281                 DUK_ASSERT(nspace >= 0 && nspace <= 10);
37282
37283                 duk_push_lstring(thr, spaces, (duk_size_t) nspace);
37284                 js_ctx->h_gap = duk_known_hstring(thr, -1);
37285                 DUK_ASSERT(js_ctx->h_gap != NULL);
37286         } else if (duk_is_string_notsymbol(thr, idx_space)) {
37287                 duk_dup(thr, idx_space);
37288                 duk_substring(thr, -1, 0, 10);  /* clamp to 10 chars */
37289                 js_ctx->h_gap = duk_known_hstring(thr, -1);
37290         } else {
37291                 /* nop */
37292         }
37293
37294         if (js_ctx->h_gap != NULL) {
37295                 /* If gap is empty, behave as if not given at all.  Check
37296                  * against byte length because character length is more
37297                  * expensive.
37298                  */
37299                 if (DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) == 0) {
37300                         js_ctx->h_gap = NULL;
37301                 }
37302         }
37303
37304         /* [ ... buf loop (proplist) (gap) ] */
37305
37306         /*
37307          *  Fast path: assume no mutation, iterate object property tables
37308          *  directly; bail out if that assumption doesn't hold.
37309          */
37310
37311 #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
37312         if (js_ctx->h_replacer == NULL &&  /* replacer is a mutation risk */
37313             js_ctx->idx_proplist == -1) {  /* proplist is very rare */
37314                 duk_int_t pcall_rc;
37315                 duk_small_uint_t prev_ms_base_flags;
37316
37317                 DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
37318
37319                 /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[]
37320                  * array so we don't need two counter checks in the fast path.  The
37321                  * slow path has a much larger recursion limit which we'll use if
37322                  * necessary.
37323                  */
37324                 DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY);
37325                 js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY;
37326                 DUK_ASSERT(js_ctx->recursion_depth == 0);
37327
37328                 /* Execute the fast path in a protected call.  If any error is thrown,
37329                  * fall back to the slow path.  This includes e.g. recursion limit
37330                  * because the fast path has a smaller recursion limit (and simpler,
37331                  * limited loop detection).
37332                  */
37333
37334                 duk_dup(thr, idx_value);
37335
37336                 /* Must prevent finalizers which may have arbitrary side effects. */
37337                 prev_ms_base_flags = thr->heap->ms_base_flags;
37338                 thr->heap->ms_base_flags |=
37339                         DUK_MS_FLAG_NO_OBJECT_COMPACTION;      /* Avoid attempt to compact any objects. */
37340                 thr->heap->pf_prevent_count++;                 /* Prevent finalizers. */
37341                 DUK_ASSERT(thr->heap->pf_prevent_count != 0);  /* Wrap. */
37342
37343                 pcall_rc = duk_safe_call(thr, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/);
37344
37345                 DUK_ASSERT(thr->heap->pf_prevent_count > 0);
37346                 thr->heap->pf_prevent_count--;
37347                 thr->heap->ms_base_flags = prev_ms_base_flags;
37348
37349                 if (pcall_rc == DUK_EXEC_SUCCESS) {
37350                         DUK_DD(DUK_DDPRINT("fast path successful"));
37351                         DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
37352                         goto replace_finished;
37353                 }
37354
37355                 /* We come here for actual aborts (like encountering .toJSON())
37356                  * but also for recursion/loop errors.  Bufwriter size can be
37357                  * kept because we'll probably need at least as much as we've
37358                  * allocated so far.
37359                  */
37360                 DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead"));
37361                 DUK_BW_RESET_SIZE(thr, &js_ctx->bw);
37362                 js_ctx->recursion_depth = 0;
37363         }
37364 #endif
37365
37366         /*
37367          *  Create wrapper object and serialize
37368          */
37369
37370         idx_holder = duk_push_object(thr);
37371         duk_dup(thr, idx_value);
37372         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_EMPTY_STRING);
37373
37374         DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
37375                              "proplist=%!T, gap=%!O, holder=%!T",
37376                              (unsigned long) js_ctx->flags,
37377                              (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop),
37378                              (duk_heaphdr *) js_ctx->h_replacer,
37379                              (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
37380                              (duk_heaphdr *) js_ctx->h_gap,
37381                              (duk_tval *) duk_get_tval(thr, -1)));
37382
37383         /* serialize the wrapper with empty string key */
37384
37385         duk_push_hstring_empty(thr);
37386
37387         /* [ ... buf loop (proplist) (gap) holder "" ] */
37388
37389         js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT;
37390         DUK_ASSERT(js_ctx->recursion_depth == 0);
37391
37392         if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) {  /* [ ... holder key ] -> [ ... holder ] */
37393                 /* Result is undefined. */
37394                 duk_push_undefined(thr);
37395         } else {
37396                 /* Convert buffer to result string. */
37397                 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
37398         }
37399
37400         DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
37401                              "proplist=%!T, gap=%!O, holder=%!T",
37402                              (unsigned long) js_ctx->flags,
37403                              (duk_tval *) duk_get_tval(thr, js_ctx->idx_loop),
37404                              (duk_heaphdr *) js_ctx->h_replacer,
37405                              (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(thr, js_ctx->idx_proplist) : NULL),
37406                              (duk_heaphdr *) js_ctx->h_gap,
37407                              (duk_tval *) duk_get_tval(thr, idx_holder)));
37408
37409         /* The stack has a variable shape here, so force it to the
37410          * desired one explicitly.
37411          */
37412
37413 #if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
37414  replace_finished:
37415 #endif
37416         duk_replace(thr, entry_top);
37417         duk_set_top(thr, entry_top + 1);
37418
37419         DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
37420                              "flags=0x%08lx, result=%!T, stack_top=%ld",
37421                              (duk_tval *) duk_get_tval(thr, idx_value),
37422                              (duk_tval *) duk_get_tval(thr, idx_replacer),
37423                              (duk_tval *) duk_get_tval(thr, idx_space),
37424                              (unsigned long) flags,
37425                              (duk_tval *) duk_get_tval(thr, -1),
37426                              (long) duk_get_top(thr)));
37427
37428         DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
37429 }
37430
37431 #if defined(DUK_USE_JSON_BUILTIN)
37432
37433 /*
37434  *  Entry points
37435  */
37436
37437 DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_hthread *thr) {
37438         duk_bi_json_parse_helper(thr,
37439                                  0 /*idx_value*/,
37440                                  1 /*idx_replacer*/,
37441                                  0 /*flags*/);
37442         return 1;
37443 }
37444
37445 DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_hthread *thr) {
37446         duk_bi_json_stringify_helper(thr,
37447                                      0 /*idx_value*/,
37448                                      1 /*idx_replacer*/,
37449                                      2 /*idx_space*/,
37450                                      0 /*flags*/);
37451         return 1;
37452 }
37453
37454 #endif  /* DUK_USE_JSON_BUILTIN */
37455
37456 #endif  /* DUK_USE_JSON_SUPPORT */
37457
37458 /* automatic undefs */
37459 #undef DUK__EMIT_1
37460 #undef DUK__EMIT_2
37461 #undef DUK__EMIT_CSTR
37462 #undef DUK__EMIT_HSTR
37463 #undef DUK__EMIT_STRIDX
37464 #undef DUK__JSON_DECSTR_BUFSIZE
37465 #undef DUK__JSON_DECSTR_CHUNKSIZE
37466 #undef DUK__JSON_ENCSTR_CHUNKSIZE
37467 #undef DUK__JSON_MAX_ESC_LEN
37468 #undef DUK__JSON_STRINGIFY_BUFSIZE
37469 #undef DUK__MKESC
37470 #undef DUK__UNEMIT_1
37471 #line 1 "duk_bi_math.c"
37472 /*
37473  *  Math built-ins
37474  */
37475
37476 /* #include duk_internal.h -> already included */
37477
37478 #if defined(DUK_USE_MATH_BUILTIN)
37479
37480 /*
37481  *  Use static helpers which can work with math.h functions matching
37482  *  the following signatures. This is not portable if any of these math
37483  *  functions is actually a macro.
37484  *
37485  *  Typing here is intentionally 'double' wherever values interact with
37486  *  the standard library APIs.
37487  */
37488
37489 typedef double (*duk__one_arg_func)(double);
37490 typedef double (*duk__two_arg_func)(double, double);
37491
37492 DUK_LOCAL duk_ret_t duk__math_minmax(duk_hthread *thr, duk_double_t initial, duk__two_arg_func min_max) {
37493         duk_idx_t n = duk_get_top(thr);
37494         duk_idx_t i;
37495         duk_double_t res = initial;
37496         duk_double_t t;
37497
37498         /*
37499          *  Note: fmax() does not match the E5 semantics.  E5 requires
37500          *  that if -any- input to Math.max() is a NaN, the result is a
37501          *  NaN.  fmax() will return a NaN only if -both- inputs are NaN.
37502          *  Same applies to fmin().
37503          *
37504          *  Note: every input value must be coerced with ToNumber(), even
37505          *  if we know the result will be a NaN anyway: ToNumber() may have
37506          *  side effects for which even order of evaluation matters.
37507          */
37508
37509         for (i = 0; i < n; i++) {
37510                 t = duk_to_number(thr, i);
37511                 if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
37512                         /* Note: not normalized, but duk_push_number() will normalize */
37513                         res = (duk_double_t) DUK_DOUBLE_NAN;
37514                 } else {
37515                         res = (duk_double_t) min_max(res, (double) t);
37516                 }
37517         }
37518
37519         duk_push_number(thr, res);
37520         return 1;
37521 }
37522
37523 DUK_LOCAL double duk__fmin_fixed(double x, double y) {
37524         /* fmin() with args -0 and +0 is not guaranteed to return
37525          * -0 as ECMAScript requires.
37526          */
37527         if (x == 0 && y == 0) {
37528                 duk_double_union du1, du2;
37529                 du1.d = x;
37530                 du2.d = y;
37531
37532                 /* Already checked to be zero so these must hold, and allow us
37533                  * to check for "x is -0 or y is -0" by ORing the high parts
37534                  * for comparison.
37535                  */
37536                 DUK_ASSERT(du1.ui[DUK_DBL_IDX_UI0] == 0 || du1.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
37537                 DUK_ASSERT(du2.ui[DUK_DBL_IDX_UI0] == 0 || du2.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
37538
37539                 /* XXX: what's the safest way of creating a negative zero? */
37540                 if ((du1.ui[DUK_DBL_IDX_UI0] | du2.ui[DUK_DBL_IDX_UI0]) != 0) {
37541                         /* Enter here if either x or y (or both) is -0. */
37542                         return -0.0;
37543                 } else {
37544                         return +0.0;
37545                 }
37546         }
37547         return duk_double_fmin(x, y);
37548 }
37549
37550 DUK_LOCAL double duk__fmax_fixed(double x, double y) {
37551         /* fmax() with args -0 and +0 is not guaranteed to return
37552          * +0 as ECMAScript requires.
37553          */
37554         if (x == 0 && y == 0) {
37555                 if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
37556                         return +0.0;
37557                 } else {
37558                         return -0.0;
37559                 }
37560         }
37561         return duk_double_fmax(x, y);
37562 }
37563
37564 #if defined(DUK_USE_ES6)
37565 DUK_LOCAL double duk__cbrt(double x) {
37566         /* cbrt() is C99.  To avoid hassling embedders with the need to provide a
37567          * cube root function, we can get by with pow().  The result is not
37568          * identical, but that's OK: ES2015 says it's implementation-dependent.
37569          */
37570
37571 #if defined(DUK_CBRT)
37572         /* cbrt() matches ES2015 requirements. */
37573         return DUK_CBRT(x);
37574 #else
37575         duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
37576
37577         /* pow() does not, however. */
37578         if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
37579                 return x;
37580         }
37581         if (DUK_SIGNBIT(x)) {
37582                 return -DUK_POW(-x, 1.0 / 3.0);
37583         } else {
37584                 return DUK_POW(x, 1.0 / 3.0);
37585         }
37586 #endif
37587 }
37588
37589 DUK_LOCAL double duk__log2(double x) {
37590 #if defined(DUK_LOG2)
37591         return DUK_LOG2(x);
37592 #else
37593         return DUK_LOG(x) * DUK_DOUBLE_LOG2E;
37594 #endif
37595 }
37596
37597 DUK_LOCAL double duk__log10(double x) {
37598 #if defined(DUK_LOG10)
37599         return DUK_LOG10(x);
37600 #else
37601         return DUK_LOG(x) * DUK_DOUBLE_LOG10E;
37602 #endif
37603 }
37604
37605 DUK_LOCAL double duk__trunc(double x) {
37606 #if defined(DUK_TRUNC)
37607         return DUK_TRUNC(x);
37608 #else
37609         /* Handles -0 correctly: -0.0 matches 'x >= 0.0' but floor()
37610          * is required to return -0 when the argument is -0.
37611          */
37612         return x >= 0.0 ? DUK_FLOOR(x) : DUK_CEIL(x);
37613 #endif
37614 }
37615 #endif  /* DUK_USE_ES6 */
37616
37617 DUK_LOCAL double duk__round_fixed(double x) {
37618         /* Numbers half-way between integers must be rounded towards +Infinity,
37619          * e.g. -3.5 must be rounded to -3 (not -4).  When rounded to zero, zero
37620          * sign must be set appropriately.  E5.1 Section 15.8.2.15.
37621          *
37622          * Note that ANSI C round() is "round to nearest integer, away from zero",
37623          * which is incorrect for negative values.  Here we make do with floor().
37624          */
37625
37626         duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
37627         if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
37628                 return x;
37629         }
37630
37631         /*
37632          *  x is finite and non-zero
37633          *
37634          *  -1.6 -> floor(-1.1) -> -2
37635          *  -1.5 -> floor(-1.0) -> -1  (towards +Inf)
37636          *  -1.4 -> floor(-0.9) -> -1
37637          *  -0.5 -> -0.0               (special case)
37638          *  -0.1 -> -0.0               (special case)
37639          *  +0.1 -> +0.0               (special case)
37640          *  +0.5 -> floor(+1.0) -> 1   (towards +Inf)
37641          *  +1.4 -> floor(+1.9) -> 1
37642          *  +1.5 -> floor(+2.0) -> 2   (towards +Inf)
37643          *  +1.6 -> floor(+2.1) -> 2
37644          */
37645
37646         if (x >= -0.5 && x < 0.5) {
37647                 /* +0.5 is handled by floor, this is on purpose */
37648                 if (x < 0.0) {
37649                         return -0.0;
37650                 } else {
37651                         return +0.0;
37652                 }
37653         }
37654
37655         return DUK_FLOOR(x + 0.5);
37656 }
37657
37658 /* Wrappers for calling standard math library methods.  These may be required
37659  * on platforms where one or more of the math built-ins are defined as macros
37660  * or inline functions and are thus not suitable to be used as function pointers.
37661  */
37662 #if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
37663 DUK_LOCAL double duk__fabs(double x) {
37664         return DUK_FABS(x);
37665 }
37666 DUK_LOCAL double duk__acos(double x) {
37667         return DUK_ACOS(x);
37668 }
37669 DUK_LOCAL double duk__asin(double x) {
37670         return DUK_ASIN(x);
37671 }
37672 DUK_LOCAL double duk__atan(double x) {
37673         return DUK_ATAN(x);
37674 }
37675 DUK_LOCAL double duk__ceil(double x) {
37676         return DUK_CEIL(x);
37677 }
37678 DUK_LOCAL double duk__cos(double x) {
37679         return DUK_COS(x);
37680 }
37681 DUK_LOCAL double duk__exp(double x) {
37682         return DUK_EXP(x);
37683 }
37684 DUK_LOCAL double duk__floor(double x) {
37685         return DUK_FLOOR(x);
37686 }
37687 DUK_LOCAL double duk__log(double x) {
37688         return DUK_LOG(x);
37689 }
37690 DUK_LOCAL double duk__sin(double x) {
37691         return DUK_SIN(x);
37692 }
37693 DUK_LOCAL double duk__sqrt(double x) {
37694         return DUK_SQRT(x);
37695 }
37696 DUK_LOCAL double duk__tan(double x) {
37697         return DUK_TAN(x);
37698 }
37699 DUK_LOCAL double duk__atan2_fixed(double x, double y) {
37700 #if defined(DUK_USE_ATAN2_WORKAROUNDS)
37701         /* Specific fixes to common atan2() implementation issues:
37702          * - test-bug-mingw-math-issues.js
37703          */
37704         if (DUK_ISINF(x) && DUK_ISINF(y)) {
37705                 if (DUK_SIGNBIT(x)) {
37706                         if (DUK_SIGNBIT(y)) {
37707                                 return -2.356194490192345;
37708                         } else {
37709                                 return -0.7853981633974483;
37710                         }
37711                 } else {
37712                         if (DUK_SIGNBIT(y)) {
37713                                 return 2.356194490192345;
37714                         } else {
37715                                 return 0.7853981633974483;
37716                         }
37717                 }
37718         }
37719 #else
37720         /* Some ISO C assumptions. */
37721         DUK_ASSERT(DUK_ATAN2(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY) == 0.7853981633974483);
37722         DUK_ASSERT(DUK_ATAN2(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY) == -0.7853981633974483);
37723         DUK_ASSERT(DUK_ATAN2(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY) == 2.356194490192345);
37724         DUK_ASSERT(DUK_ATAN2(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY) == -2.356194490192345);
37725 #endif
37726
37727         return DUK_ATAN2(x, y);
37728 }
37729 #endif  /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
37730
37731 /* order must match constants in genbuiltins.py */
37732 DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
37733 #if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
37734         duk__fabs,
37735         duk__acos,
37736         duk__asin,
37737         duk__atan,
37738         duk__ceil,
37739         duk__cos,
37740         duk__exp,
37741         duk__floor,
37742         duk__log,
37743         duk__round_fixed,
37744         duk__sin,
37745         duk__sqrt,
37746         duk__tan,
37747 #if defined(DUK_USE_ES6)
37748         duk__cbrt,
37749         duk__log2,
37750         duk__log10,
37751         duk__trunc
37752 #endif
37753 #else  /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
37754         DUK_FABS,
37755         DUK_ACOS,
37756         DUK_ASIN,
37757         DUK_ATAN,
37758         DUK_CEIL,
37759         DUK_COS,
37760         DUK_EXP,
37761         DUK_FLOOR,
37762         DUK_LOG,
37763         duk__round_fixed,
37764         DUK_SIN,
37765         DUK_SQRT,
37766         DUK_TAN,
37767 #if defined(DUK_USE_ES6)
37768         duk__cbrt,
37769         duk__log2,
37770         duk__log10,
37771         duk__trunc
37772 #endif
37773 #endif  /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
37774 };
37775
37776 /* order must match constants in genbuiltins.py */
37777 DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
37778 #if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
37779         duk__atan2_fixed,
37780         duk_js_arith_pow
37781 #else
37782         duk__atan2_fixed,
37783         duk_js_arith_pow
37784 #endif
37785 };
37786
37787 DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_hthread *thr) {
37788         duk_small_int_t fun_idx = duk_get_current_magic(thr);
37789         duk__one_arg_func fun;
37790         duk_double_t arg1;
37791
37792         DUK_ASSERT(fun_idx >= 0);
37793         DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
37794         arg1 = duk_to_number(thr, 0);
37795         fun = duk__one_arg_funcs[fun_idx];
37796         duk_push_number(thr, (duk_double_t) fun((double) arg1));
37797         return 1;
37798 }
37799
37800 DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_hthread *thr) {
37801         duk_small_int_t fun_idx = duk_get_current_magic(thr);
37802         duk__two_arg_func fun;
37803         duk_double_t arg1;
37804         duk_double_t arg2;
37805
37806         DUK_ASSERT(fun_idx >= 0);
37807         DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
37808         arg1 = duk_to_number(thr, 0);  /* explicit ordered evaluation to match coercion semantics */
37809         arg2 = duk_to_number(thr, 1);
37810         fun = duk__two_arg_funcs[fun_idx];
37811         duk_push_number(thr, (duk_double_t) fun((double) arg1, (double) arg2));
37812         return 1;
37813 }
37814
37815 DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_hthread *thr) {
37816         return duk__math_minmax(thr, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
37817 }
37818
37819 DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_hthread *thr) {
37820         return duk__math_minmax(thr, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
37821 }
37822
37823 DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_hthread *thr) {
37824         duk_push_number(thr, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE(thr));
37825         return 1;
37826 }
37827
37828 #if defined(DUK_USE_ES6)
37829 DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_hthread *thr) {
37830         /*
37831          *  E6 Section 20.2.2.18: Math.hypot
37832          *
37833          *  - If no arguments are passed, the result is +0.
37834          *  - If any argument is +inf, the result is +inf.
37835          *  - If any argument is -inf, the result is +inf.
37836          *  - If no argument is +inf or -inf, and any argument is NaN, the result is
37837          *    NaN.
37838          *  - If all arguments are either +0 or -0, the result is +0.
37839          */
37840
37841         duk_idx_t nargs;
37842         duk_idx_t i;
37843         duk_bool_t found_nan;
37844         duk_double_t max;
37845         duk_double_t sum, summand;
37846         duk_double_t comp, prelim;
37847         duk_double_t t;
37848
37849         nargs = duk_get_top(thr);
37850
37851         /* Find the highest value.  Also ToNumber() coerces. */
37852         max = 0.0;
37853         found_nan = 0;
37854         for (i = 0; i < nargs; i++) {
37855                 t = DUK_FABS(duk_to_number(thr, i));
37856                 if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) {
37857                         found_nan = 1;
37858                 } else {
37859                         max = duk_double_fmax(max, t);
37860                 }
37861         }
37862
37863         /* Early return cases. */
37864         if (max == DUK_DOUBLE_INFINITY) {
37865                 duk_push_number(thr, DUK_DOUBLE_INFINITY);
37866                 return 1;
37867         } else if (found_nan) {
37868                 duk_push_number(thr, DUK_DOUBLE_NAN);
37869                 return 1;
37870         } else if (max == 0.0) {
37871                 duk_push_number(thr, 0.0);
37872                 /* Otherwise we'd divide by zero. */
37873                 return 1;
37874         }
37875
37876         /* Use Kahan summation and normalize to the highest value to minimize
37877          * floating point rounding error and avoid overflow.
37878          *
37879          * https://en.wikipedia.org/wiki/Kahan_summation_algorithm
37880          */
37881         sum = 0.0;
37882         comp = 0.0;
37883         for (i = 0; i < nargs; i++) {
37884                 t = DUK_FABS(duk_get_number(thr, i)) / max;
37885                 summand = (t * t) - comp;
37886                 prelim = sum + summand;
37887                 comp = (prelim - sum) - summand;
37888                 sum = prelim;
37889         }
37890
37891         duk_push_number(thr, (duk_double_t) DUK_SQRT(sum) * max);
37892         return 1;
37893 }
37894 #endif  /* DUK_USE_ES6 */
37895
37896 #if defined(DUK_USE_ES6)
37897 DUK_INTERNAL duk_ret_t duk_bi_math_object_sign(duk_hthread *thr) {
37898         duk_double_t d;
37899
37900         d = duk_to_number(thr, 0);
37901         if (duk_double_is_nan(d)) {
37902                 DUK_ASSERT(duk_is_nan(thr, -1));
37903                 return 1;  /* NaN input -> return NaN */
37904         }
37905         if (d == 0.0) {
37906                 /* Zero sign kept, i.e. -0 -> -0, +0 -> +0. */
37907                 return 1;
37908         }
37909         duk_push_int(thr, (d > 0.0 ? 1 : -1));
37910         return 1;
37911 }
37912 #endif  /* DUK_USE_ES6 */
37913
37914 #if defined(DUK_USE_ES6)
37915 DUK_INTERNAL duk_ret_t duk_bi_math_object_clz32(duk_hthread *thr) {
37916         duk_uint32_t x;
37917         duk_small_uint_t i;
37918
37919 #if defined(DUK_USE_PREFER_SIZE)
37920         duk_uint32_t mask;
37921
37922         x = duk_to_uint32(thr, 0);
37923         for (i = 0, mask = 0x80000000UL; mask != 0; mask >>= 1) {
37924                 if (x & mask) {
37925                         break;
37926                 }
37927                 i++;
37928         }
37929         DUK_ASSERT(i <= 32);
37930         duk_push_uint(thr, i);
37931         return 1;
37932 #else  /* DUK_USE_PREFER_SIZE */
37933         i = 0;
37934         x = duk_to_uint32(thr, 0);
37935         if (x & 0xffff0000UL) {
37936                 x >>= 16;
37937         } else {
37938                 i += 16;
37939         }
37940         if (x & 0x0000ff00UL) {
37941                 x >>= 8;
37942         } else {
37943                 i += 8;
37944         }
37945         if (x & 0x000000f0UL) {
37946                 x >>= 4;
37947         } else {
37948                 i += 4;
37949         }
37950         if (x & 0x0000000cUL) {
37951                 x >>= 2;
37952         } else {
37953                 i += 2;
37954         }
37955         if (x & 0x00000002UL) {
37956                 x >>= 1;
37957         } else {
37958                 i += 1;
37959         }
37960         if (x & 0x00000001UL) {
37961                 ;
37962         } else {
37963                 i += 1;
37964         }
37965         DUK_ASSERT(i <= 32);
37966         duk_push_uint(thr, i);
37967         return 1;
37968 #endif  /* DUK_USE_PREFER_SIZE */
37969 }
37970 #endif  /* DUK_USE_ES6 */
37971
37972 #if defined(DUK_USE_ES6)
37973 DUK_INTERNAL duk_ret_t duk_bi_math_object_imul(duk_hthread *thr) {
37974         duk_uint32_t x, y, z;
37975
37976         x = duk_to_uint32(thr, 0);
37977         y = duk_to_uint32(thr, 1);
37978         z = x * y;
37979
37980         /* While arguments are ToUint32() coerced and the multiplication
37981          * is unsigned as such, the final result is curiously interpreted
37982          * as a signed 32-bit value.
37983          */
37984         duk_push_i32(thr, (duk_int32_t) z);
37985         return 1;
37986 }
37987 #endif  /* DUK_USE_ES6 */
37988
37989 #endif  /* DUK_USE_MATH_BUILTIN */
37990 #line 1 "duk_bi_number.c"
37991 /*
37992  *  Number built-ins
37993  */
37994
37995 /* #include duk_internal.h -> already included */
37996
37997 #if defined(DUK_USE_NUMBER_BUILTIN)
37998
37999 DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_hthread *thr) {
38000         duk_hobject *h;
38001
38002         /* Number built-in accepts a plain number or a Number object (whose
38003          * internal value is operated on).  Other types cause TypeError.
38004          */
38005
38006         duk_push_this(thr);
38007         if (duk_is_number(thr, -1)) {
38008                 DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
38009                 goto done;
38010         }
38011         h = duk_get_hobject(thr, -1);
38012         if (!h ||
38013             (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
38014                 DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(thr, -1)));
38015                 DUK_ERROR_TYPE(thr, "number expected");
38016                 DUK_WO_NORETURN(return 0.0;);
38017         }
38018         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
38019         DUK_ASSERT(duk_is_number(thr, -1));
38020         DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
38021                              (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
38022         duk_remove_m2(thr);
38023
38024  done:
38025         return duk_get_number(thr, -1);
38026 }
38027
38028 DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_hthread *thr) {
38029         duk_idx_t nargs;
38030         duk_hobject *h_this;
38031
38032         /*
38033          *  The Number constructor uses ToNumber(arg) for number coercion
38034          *  (coercing an undefined argument to NaN).  However, if the
38035          *  argument is not given at all, +0 must be used instead.  To do
38036          *  this, a vararg function is used.
38037          */
38038
38039         nargs = duk_get_top(thr);
38040         if (nargs == 0) {
38041                 duk_push_int(thr, 0);
38042         }
38043         duk_to_number(thr, 0);
38044         duk_set_top(thr, 1);
38045         DUK_ASSERT_TOP(thr, 1);
38046
38047         if (!duk_is_constructor_call(thr)) {
38048                 return 1;
38049         }
38050
38051         /*
38052          *  E5 Section 15.7.2.1 requires that the constructed object
38053          *  must have the original Number.prototype as its internal
38054          *  prototype.  However, since Number.prototype is non-writable
38055          *  and non-configurable, this doesn't have to be enforced here:
38056          *  The default object (bound to 'this') is OK, though we have
38057          *  to change its class.
38058          *
38059          *  Internal value set to ToNumber(arg) or +0; if no arg given,
38060          *  ToNumber(undefined) = NaN, so special treatment is needed
38061          *  (above).  String internal value is immutable.
38062          */
38063
38064         /* XXX: helper */
38065         duk_push_this(thr);
38066         h_this = duk_known_hobject(thr, -1);
38067         DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
38068
38069         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
38070         DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
38071         DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
38072
38073         duk_dup_0(thr);  /* -> [ val obj val ] */
38074         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
38075         return 0;  /* no return value -> don't replace created value */
38076 }
38077
38078 DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_hthread *thr) {
38079         (void) duk__push_this_number_plain(thr);
38080         return 1;
38081 }
38082
38083 DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_hthread *thr) {
38084         duk_small_int_t radix;
38085         duk_small_uint_t n2s_flags;
38086
38087         (void) duk__push_this_number_plain(thr);
38088         if (duk_is_undefined(thr, 0)) {
38089                 radix = 10;
38090         } else {
38091                 radix = (duk_small_int_t) duk_to_int_check_range(thr, 0, 2, 36);
38092         }
38093         DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
38094
38095         n2s_flags = 0;
38096
38097         duk_numconv_stringify(thr,
38098                               radix /*radix*/,
38099                               0 /*digits*/,
38100                               n2s_flags /*flags*/);
38101         return 1;
38102 }
38103
38104 DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_hthread *thr) {
38105         /* XXX: just use toString() for now; permitted although not recommended.
38106          * nargs==1, so radix is passed to toString().
38107          */
38108         return duk_bi_number_prototype_to_string(thr);
38109 }
38110
38111 /*
38112  *  toFixed(), toExponential(), toPrecision()
38113  */
38114
38115 /* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
38116
38117 DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_hthread *thr) {
38118         duk_small_int_t frac_digits;
38119         duk_double_t d;
38120         duk_small_int_t c;
38121         duk_small_uint_t n2s_flags;
38122
38123         /* In ES5.1 frac_digits is coerced first; in ES2015 the 'this number
38124          * value' check is done first.
38125          */
38126         d = duk__push_this_number_plain(thr);
38127         frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
38128
38129         c = (duk_small_int_t) DUK_FPCLASSIFY(d);
38130         if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
38131                 goto use_to_string;
38132         }
38133
38134         if (d >= 1.0e21 || d <= -1.0e21) {
38135                 goto use_to_string;
38136         }
38137
38138         n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
38139                     DUK_N2S_FLAG_FRACTION_DIGITS;
38140
38141         duk_numconv_stringify(thr,
38142                               10 /*radix*/,
38143                               frac_digits /*digits*/,
38144                               n2s_flags /*flags*/);
38145         return 1;
38146
38147  use_to_string:
38148         DUK_ASSERT_TOP(thr, 2);
38149         duk_to_string(thr, -1);
38150         return 1;
38151 }
38152
38153 DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_hthread *thr) {
38154         duk_bool_t frac_undefined;
38155         duk_small_int_t frac_digits;
38156         duk_double_t d;
38157         duk_small_int_t c;
38158         duk_small_uint_t n2s_flags;
38159
38160         d = duk__push_this_number_plain(thr);
38161
38162         frac_undefined = duk_is_undefined(thr, 0);
38163         duk_to_int(thr, 0);  /* for side effects */
38164
38165         c = (duk_small_int_t) DUK_FPCLASSIFY(d);
38166         if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
38167                 goto use_to_string;
38168         }
38169
38170         frac_digits = (duk_small_int_t) duk_to_int_check_range(thr, 0, 0, 20);
38171
38172         n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
38173                    (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
38174
38175         duk_numconv_stringify(thr,
38176                               10 /*radix*/,
38177                               frac_digits + 1 /*leading digit + fractions*/,
38178                               n2s_flags /*flags*/);
38179         return 1;
38180
38181  use_to_string:
38182         DUK_ASSERT_TOP(thr, 2);
38183         duk_to_string(thr, -1);
38184         return 1;
38185 }
38186
38187 DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) {
38188         /* The specification has quite awkward order of coercion and
38189          * checks for toPrecision().  The operations below are a bit
38190          * reordered, within constraints of observable side effects.
38191          */
38192
38193         duk_double_t d;
38194         duk_small_int_t prec;
38195         duk_small_int_t c;
38196         duk_small_uint_t n2s_flags;
38197
38198         DUK_ASSERT_TOP(thr, 1);
38199
38200         d = duk__push_this_number_plain(thr);
38201         if (duk_is_undefined(thr, 0)) {
38202                 goto use_to_string;
38203         }
38204         DUK_ASSERT_TOP(thr, 2);
38205
38206         duk_to_int(thr, 0);  /* for side effects */
38207
38208         c = (duk_small_int_t) DUK_FPCLASSIFY(d);
38209         if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
38210                 goto use_to_string;
38211         }
38212
38213         prec = (duk_small_int_t) duk_to_int_check_range(thr, 0, 1, 21);
38214
38215         n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
38216                     DUK_N2S_FLAG_NO_ZERO_PAD;
38217
38218         duk_numconv_stringify(thr,
38219                               10 /*radix*/,
38220                               prec /*digits*/,
38221                               n2s_flags /*flags*/);
38222         return 1;
38223
38224  use_to_string:
38225         /* Used when precision is undefined; also used for NaN (-> "NaN"),
38226          * and +/- infinity (-> "Infinity", "-Infinity").
38227          */
38228
38229         DUK_ASSERT_TOP(thr, 2);
38230         duk_to_string(thr, -1);
38231         return 1;
38232 }
38233
38234 /*
38235  *  ES2015 isFinite() etc
38236  */
38237
38238 #if defined(DUK_USE_ES6)
38239 DUK_INTERNAL duk_ret_t duk_bi_number_check_shared(duk_hthread *thr) {
38240         duk_int_t magic;
38241         duk_bool_t ret = 0;
38242
38243         if (duk_is_number(thr, 0)) {
38244                 duk_double_t d;
38245
38246                 magic = duk_get_current_magic(thr);
38247                 d = duk_get_number(thr, 0);
38248
38249                 switch (magic) {
38250                 case 0:  /* isFinite() */
38251                         ret = duk_double_is_finite(d);
38252                         break;
38253                 case 1:  /* isInteger() */
38254                         ret = duk_double_is_integer(d);
38255                         break;
38256                 case 2:  /* isNaN() */
38257                         ret = duk_double_is_nan(d);
38258                         break;
38259                 default:  /* isSafeInteger() */
38260                         DUK_ASSERT(magic == 3);
38261                         ret = duk_double_is_safe_integer(d);
38262                 }
38263         }
38264
38265         duk_push_boolean(thr, ret);
38266         return 1;
38267 }
38268 #endif  /* DUK_USE_ES6 */
38269
38270 #endif  /* DUK_USE_NUMBER_BUILTIN */
38271 #line 1 "duk_bi_object.c"
38272 /*
38273  *  Object built-ins
38274  */
38275
38276 /* #include duk_internal.h -> already included */
38277
38278 /* Needed even when Object built-in disabled. */
38279 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_hthread *thr) {
38280         duk_tval *tv;
38281
38282         tv = DUK_HTHREAD_THIS_PTR(thr);
38283         duk_push_class_string_tval(thr, tv, 0 /*avoid_side_effects*/);
38284         return 1;
38285 }
38286
38287 #if defined(DUK_USE_OBJECT_BUILTIN)
38288 DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_hthread *thr) {
38289         duk_uint_t arg_mask;
38290
38291         arg_mask = duk_get_type_mask(thr, 0);
38292
38293         if (!duk_is_constructor_call(thr) &&  /* not a constructor call */
38294             ((arg_mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) == 0)) {  /* and argument not null or undefined */
38295                 duk_to_object(thr, 0);
38296                 return 1;
38297         }
38298
38299         /* Pointer and buffer primitive values are treated like other
38300          * primitives values which have a fully fledged object counterpart:
38301          * promote to an object value.  Lightfuncs and plain buffers are
38302          * coerced with ToObject() even they could also be returned as is.
38303          */
38304         if (arg_mask & (DUK_TYPE_MASK_OBJECT |
38305                         DUK_TYPE_MASK_STRING |
38306                         DUK_TYPE_MASK_BOOLEAN |
38307                         DUK_TYPE_MASK_NUMBER |
38308                         DUK_TYPE_MASK_POINTER |
38309                         DUK_TYPE_MASK_BUFFER |
38310                         DUK_TYPE_MASK_LIGHTFUNC)) {
38311                 /* For DUK_TYPE_OBJECT the coercion is a no-op and could
38312                  * be checked for explicitly, but Object(obj) calls are
38313                  * not very common so opt for minimal footprint.
38314                  */
38315                 duk_to_object(thr, 0);
38316                 return 1;
38317         }
38318
38319         (void) duk_push_object_helper(thr,
38320                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
38321                                       DUK_HOBJECT_FLAG_FASTREFS |
38322                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
38323                                       DUK_BIDX_OBJECT_PROTOTYPE);
38324         return 1;
38325 }
38326 #endif  /* DUK_USE_OBJECT_BUILTIN */
38327
38328 #if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
38329 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_hthread *thr) {
38330         duk_idx_t nargs;
38331         duk_int_t idx;
38332
38333         nargs = duk_get_top_require_min(thr, 1 /*min_top*/);
38334
38335         duk_to_object(thr, 0);
38336         for (idx = 1; idx < nargs; idx++) {
38337                 /* E7 19.1.2.1 (step 4a) */
38338                 if (duk_is_null_or_undefined(thr, idx)) {
38339                         continue;
38340                 }
38341
38342                 /* duk_enum() respects ES2015+ [[OwnPropertyKeys]] ordering, which is
38343                  * convenient here.
38344                  */
38345                 duk_to_object(thr, idx);
38346                 duk_enum(thr, idx, DUK_ENUM_OWN_PROPERTIES_ONLY);
38347                 while (duk_next(thr, -1, 1 /*get_value*/)) {
38348                         /* [ target ... enum key value ] */
38349                         duk_put_prop(thr, 0);
38350                         /* [ target ... enum ] */
38351                 }
38352                 /* Could pop enumerator, but unnecessary because of duk_set_top()
38353                  * below.
38354                  */
38355         }
38356
38357         duk_set_top(thr, 1);
38358         return 1;
38359 }
38360 #endif
38361
38362 #if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
38363 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_hthread *thr) {
38364         DUK_ASSERT_TOP(thr, 2);
38365         duk_push_boolean(thr, duk_samevalue(thr, 0, 1));
38366         return 1;
38367 }
38368 #endif
38369
38370 #if defined(DUK_USE_OBJECT_BUILTIN)
38371 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_hthread *thr) {
38372         duk_hobject *proto;
38373
38374         DUK_ASSERT_TOP(thr, 2);
38375
38376 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
38377         duk_hbufobj_promote_plain(thr, 0);
38378 #endif
38379         proto = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_NULL);
38380         DUK_ASSERT(proto != NULL || duk_is_null(thr, 0));
38381
38382         (void) duk_push_object_helper_proto(thr,
38383                                             DUK_HOBJECT_FLAG_EXTENSIBLE |
38384                                             DUK_HOBJECT_FLAG_FASTREFS |
38385                                             DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
38386                                             proto);
38387
38388         if (!duk_is_undefined(thr, 1)) {
38389                 /* [ O Properties obj ] */
38390
38391                 duk_replace(thr, 0);
38392
38393                 /* [ obj Properties ] */
38394
38395                 /* Just call the "original" Object.defineProperties() to
38396                  * finish up.
38397                  */
38398
38399                 return duk_bi_object_constructor_define_properties(thr);
38400         }
38401
38402         /* [ O Properties obj ] */
38403
38404         return 1;
38405 }
38406 #endif  /* DUK_USE_OBJECT_BUILTIN */
38407
38408 #if defined(DUK_USE_OBJECT_BUILTIN)
38409 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_hthread *thr) {
38410         duk_small_uint_t pass;
38411         duk_uint_t defprop_flags;
38412         duk_hobject *obj;
38413         duk_idx_t idx_value;
38414         duk_hobject *get;
38415         duk_hobject *set;
38416
38417         /* Lightfunc and plain buffer handling by ToObject() coercion. */
38418         obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
38419         DUK_ASSERT(obj != NULL);
38420
38421         duk_to_object(thr, 1);        /* properties object */
38422
38423         DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
38424                              (duk_tval *) duk_get_tval(thr, 0),
38425                              (duk_tval *) duk_get_tval(thr, 1)));
38426
38427         /*
38428          *  Two pass approach to processing the property descriptors.
38429          *  On first pass validate and normalize all descriptors before
38430          *  any changes are made to the target object.  On second pass
38431          *  make the actual modifications to the target object.
38432          *
38433          *  Right now we'll just use the same normalize/validate helper
38434          *  on both passes, ignoring its outputs on the first pass.
38435          */
38436
38437         for (pass = 0; pass < 2; pass++) {
38438                 duk_set_top(thr, 2);  /* -> [ hobject props ] */
38439                 duk_enum(thr, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/);
38440
38441                 for (;;) {
38442                         duk_hstring *key;
38443
38444                         /* [ hobject props enum(props) ] */
38445
38446                         duk_set_top(thr, 3);
38447
38448                         if (!duk_next(thr, 2, 1 /*get_value*/)) {
38449                                 break;
38450                         }
38451
38452                         DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
38453                                              (duk_tval *) duk_get_tval(thr, -2),
38454                                              (duk_tval *) duk_get_tval(thr, -1)));
38455
38456                         /* [ hobject props enum(props) key desc ] */
38457
38458                         duk_hobject_prepare_property_descriptor(thr,
38459                                                                 4 /*idx_desc*/,
38460                                                                 &defprop_flags,
38461                                                                 &idx_value,
38462                                                                 &get,
38463                                                                 &set);
38464
38465                         /* [ hobject props enum(props) key desc [multiple values] ] */
38466
38467                         if (pass == 0) {
38468                                 continue;
38469                         }
38470
38471                         /* This allows symbols on purpose. */
38472                         key = duk_known_hstring(thr, 3);
38473                         DUK_ASSERT(key != NULL);
38474
38475                         duk_hobject_define_property_helper(thr,
38476                                                            defprop_flags,
38477                                                            obj,
38478                                                            key,
38479                                                            idx_value,
38480                                                            get,
38481                                                            set,
38482                                                            1 /*throw_flag*/);
38483                 }
38484         }
38485
38486         /*
38487          *  Return target object
38488          */
38489
38490         duk_dup_0(thr);
38491         return 1;
38492 }
38493 #endif  /* DUK_USE_OBJECT_BUILTIN */
38494
38495 #if defined(DUK_USE_OBJECT_BUILTIN)
38496 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_hthread *thr) {
38497         DUK_ASSERT_TOP(thr, 1);
38498
38499         duk_seal_freeze_raw(thr, 0, (duk_bool_t) duk_get_current_magic(thr) /*is_freeze*/);
38500         return 1;
38501 }
38502 #endif  /* DUK_USE_OBJECT_BUILTIN */
38503
38504 #if defined(DUK_USE_OBJECT_BUILTIN)
38505 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_hthread *thr) {
38506         duk_hobject *h;
38507         duk_bool_t is_frozen;
38508         duk_uint_t mask;
38509
38510         is_frozen = (duk_bool_t) duk_get_current_magic(thr);
38511         mask = duk_get_type_mask(thr, 0);
38512         if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
38513                 DUK_ASSERT(is_frozen == 0 || is_frozen == 1);
38514                 duk_push_boolean(thr, (mask & DUK_TYPE_MASK_LIGHTFUNC) ?
38515                                           1 :               /* lightfunc always frozen and sealed */
38516                                           (is_frozen ^ 1)); /* buffer sealed but not frozen (index props writable) */
38517         } else {
38518                 /* ES2015 Sections 19.1.2.12, 19.1.2.13: anything other than an object
38519                  * is considered to be already sealed and frozen.
38520                  */
38521                 h = duk_get_hobject(thr, 0);
38522                 duk_push_boolean(thr, (h == NULL) ||
38523                                       duk_hobject_object_is_sealed_frozen_helper(thr, h, is_frozen /*is_frozen*/));
38524         }
38525         return 1;
38526 }
38527 #endif  /* DUK_USE_OBJECT_BUILTIN */
38528
38529 #if defined(DUK_USE_OBJECT_BUILTIN)
38530 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_hthread *thr) {
38531         DUK_ASSERT_TOP(thr, 0);
38532         (void) duk_push_this_coercible_to_object(thr);
38533         duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_TO_STRING);
38534 #if 0  /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */
38535         duk_require_callable(thr, 1);
38536 #endif
38537         duk_dup_0(thr);  /* -> [ O toString O ] */
38538         duk_call_method(thr, 0);  /* XXX: call method tail call? */
38539         return 1;
38540 }
38541 #endif  /* DUK_USE_OBJECT_BUILTIN */
38542
38543 #if defined(DUK_USE_OBJECT_BUILTIN)
38544 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_hthread *thr) {
38545         /* For lightfuncs and plain buffers, returns Object() coerced. */
38546         (void) duk_push_this_coercible_to_object(thr);
38547         return 1;
38548 }
38549 #endif  /* DUK_USE_OBJECT_BUILTIN */
38550
38551 #if defined(DUK_USE_OBJECT_BUILTIN)
38552 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_hthread *thr) {
38553         duk_hobject *h_v;
38554         duk_hobject *h_obj;
38555
38556         DUK_ASSERT_TOP(thr, 1);
38557
38558         h_v = duk_get_hobject(thr, 0);
38559         if (!h_v) {
38560                 duk_push_false(thr);  /* XXX: tail call: return duk_push_false(thr) */
38561                 return 1;
38562         }
38563
38564         h_obj = duk_push_this_coercible_to_object(thr);
38565         DUK_ASSERT(h_obj != NULL);
38566
38567         /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
38568          * Prototype loops should cause an error to be thrown.
38569          */
38570         duk_push_boolean(thr, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
38571         return 1;
38572 }
38573 #endif  /* DUK_USE_OBJECT_BUILTIN */
38574
38575 #if defined(DUK_USE_OBJECT_BUILTIN)
38576 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_hthread *thr) {
38577         return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, 0 /*required_desc_flags*/);
38578 }
38579 #endif  /* DUK_USE_OBJECT_BUILTIN */
38580
38581 #if defined(DUK_USE_OBJECT_BUILTIN)
38582 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_hthread *thr) {
38583         return (duk_ret_t) duk_hobject_object_ownprop_helper(thr, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
38584 }
38585 #endif  /* DUK_USE_OBJECT_BUILTIN */
38586
38587 #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
38588 /* Shared helper to implement Object.getPrototypeOf,
38589  * Object.prototype.__proto__ getter, and Reflect.getPrototypeOf.
38590  *
38591  * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
38592  */
38593 DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_hthread *thr) {
38594         /*
38595          *  magic = 0: __proto__ getter
38596          *  magic = 1: Object.getPrototypeOf()
38597          *  magic = 2: Reflect.getPrototypeOf()
38598          */
38599
38600         duk_hobject *h;
38601         duk_hobject *proto;
38602         duk_tval *tv;
38603         duk_int_t magic;
38604
38605         magic = duk_get_current_magic(thr);
38606
38607         if (magic == 0) {
38608                 DUK_ASSERT_TOP(thr, 0);
38609                 duk_push_this_coercible_to_object(thr);
38610         }
38611         DUK_ASSERT(duk_get_top(thr) >= 1);
38612         if (magic < 2) {
38613                 /* ES2015 Section 19.1.2.9, step 1 */
38614                 duk_to_object(thr, 0);
38615         }
38616         tv = DUK_GET_TVAL_POSIDX(thr, 0);
38617
38618         switch (DUK_TVAL_GET_TAG(tv)) {
38619         case DUK_TAG_BUFFER:
38620                 proto = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
38621                 break;
38622         case DUK_TAG_LIGHTFUNC:
38623                 proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
38624                 break;
38625         case DUK_TAG_OBJECT:
38626                 h = DUK_TVAL_GET_OBJECT(tv);
38627                 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
38628                 break;
38629         default:
38630                 /* This implicitly handles CheckObjectCoercible() caused
38631                  * TypeError.
38632                  */
38633                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
38634         }
38635         if (proto != NULL) {
38636                 duk_push_hobject(thr, proto);
38637         } else {
38638                 duk_push_null(thr);
38639         }
38640         return 1;
38641 }
38642 #endif  /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
38643
38644 #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
38645 /* Shared helper to implement ES2015 Object.setPrototypeOf,
38646  * Object.prototype.__proto__ setter, and Reflect.setPrototypeOf.
38647  *
38648  * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
38649  * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
38650  */
38651 DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) {
38652         /*
38653          *  magic = 0: __proto__ setter
38654          *  magic = 1: Object.setPrototypeOf()
38655          *  magic = 2: Reflect.setPrototypeOf()
38656          */
38657
38658         duk_hobject *h_obj;
38659         duk_hobject *h_new_proto;
38660         duk_hobject *h_curr;
38661         duk_ret_t ret_success = 1;  /* retval for success path */
38662         duk_uint_t mask;
38663         duk_int_t magic;
38664
38665         /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */
38666         magic = duk_get_current_magic(thr);
38667         if (magic == 0) {
38668                 duk_push_this_check_object_coercible(thr);
38669                 duk_insert(thr, 0);
38670                 if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
38671                         return 0;
38672                 }
38673
38674                 /* __proto__ setter returns 'undefined' on success unlike the
38675                  * setPrototypeOf() call which returns the target object.
38676                  */
38677                 ret_success = 0;
38678         } else {
38679                 if (magic == 1) {
38680                         duk_require_object_coercible(thr, 0);
38681                 } else {
38682                         duk_require_hobject_accept_mask(thr, 0,
38683                                                         DUK_TYPE_MASK_LIGHTFUNC |
38684                                                         DUK_TYPE_MASK_BUFFER);
38685                 }
38686                 duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
38687         }
38688
38689         h_new_proto = duk_get_hobject(thr, 1);
38690         /* h_new_proto may be NULL */
38691
38692         mask = duk_get_type_mask(thr, 0);
38693         if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
38694                 duk_hobject *curr_proto;
38695                 curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ?
38696                                                DUK_BIDX_FUNCTION_PROTOTYPE :
38697                                                DUK_BIDX_UINT8ARRAY_PROTOTYPE];
38698                 if (h_new_proto == curr_proto) {
38699                         goto skip;
38700                 }
38701                 goto fail_nonextensible;
38702         }
38703         h_obj = duk_get_hobject(thr, 0);
38704         if (h_obj == NULL) {
38705                 goto skip;
38706         }
38707         DUK_ASSERT(h_obj != NULL);
38708
38709         /* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */
38710         /* TODO: implement Proxy object support here */
38711
38712         if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
38713                 goto skip;
38714         }
38715         if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
38716                 goto fail_nonextensible;
38717         }
38718         for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
38719                 /* Loop prevention. */
38720                 if (h_curr == h_obj) {
38721                         goto fail_loop;
38722                 }
38723         }
38724         DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
38725         /* fall thru */
38726
38727  skip:
38728         duk_set_top(thr, 1);
38729         if (magic == 2) {
38730                 duk_push_true(thr);
38731         }
38732         return ret_success;
38733
38734  fail_nonextensible:
38735  fail_loop:
38736         if (magic != 2) {
38737                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
38738         } else {
38739                 duk_push_false(thr);
38740                 return 1;
38741         }
38742 }
38743 #endif  /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
38744
38745 #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
38746 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_hthread *thr) {
38747         /*
38748          *  magic = 0: Object.defineProperty()
38749          *  magic = 1: Reflect.defineProperty()
38750          */
38751
38752         duk_hobject *obj;
38753         duk_hstring *key;
38754         duk_hobject *get;
38755         duk_hobject *set;
38756         duk_idx_t idx_value;
38757         duk_uint_t defprop_flags;
38758         duk_small_uint_t magic;
38759         duk_bool_t throw_flag;
38760         duk_bool_t ret;
38761
38762         DUK_ASSERT(thr != NULL);
38763
38764         DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
38765                              (void *) thr,
38766                              (duk_tval *) duk_get_tval(thr, 0),
38767                              (duk_tval *) duk_get_tval(thr, 1),
38768                              (duk_tval *) duk_get_tval(thr, 2)));
38769
38770         /* [ obj key desc ] */
38771
38772         magic = (duk_small_uint_t) duk_get_current_magic(thr);
38773
38774         /* Lightfuncs are currently supported by coercing to a temporary
38775          * Function object; changes will be allowed (the coerced value is
38776          * extensible) but will be lost.  Same for plain buffers.
38777          */
38778         obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
38779         DUK_ASSERT(obj != NULL);
38780         key = duk_to_property_key_hstring(thr, 1);
38781         (void) duk_require_hobject(thr, 2);
38782
38783         DUK_ASSERT(obj != NULL);
38784         DUK_ASSERT(key != NULL);
38785         DUK_ASSERT(duk_get_hobject(thr, 2) != NULL);
38786
38787         /*
38788          *  Validate and convert argument property descriptor (an ECMAScript
38789          *  object) into a set of defprop_flags and possibly property value,
38790          *  getter, and/or setter values on the value stack.
38791          *
38792          *  Lightfunc set/get values are coerced to full Functions.
38793          */
38794
38795         duk_hobject_prepare_property_descriptor(thr,
38796                                                 2 /*idx_desc*/,
38797                                                 &defprop_flags,
38798                                                 &idx_value,
38799                                                 &get,
38800                                                 &set);
38801
38802         /*
38803          *  Use Object.defineProperty() helper for the actual operation.
38804          */
38805
38806         DUK_ASSERT(magic == 0U || magic == 1U);
38807         throw_flag = magic ^ 1U;
38808         ret = duk_hobject_define_property_helper(thr,
38809                                                  defprop_flags,
38810                                                  obj,
38811                                                  key,
38812                                                  idx_value,
38813                                                  get,
38814                                                  set,
38815                                                  throw_flag);
38816
38817         /* Ignore the normalize/validate helper outputs on the value stack,
38818          * they're popped automatically.
38819          */
38820
38821         if (magic == 0U) {
38822                 /* Object.defineProperty(): return target object. */
38823                 duk_push_hobject(thr, obj);
38824         } else {
38825                 /* Reflect.defineProperty(): return success/fail. */
38826                 duk_push_boolean(thr, ret);
38827         }
38828         return 1;
38829 }
38830 #endif  /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
38831
38832 #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
38833 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_hthread *thr) {
38834         DUK_ASSERT_TOP(thr, 2);
38835
38836         /* ES2015 Section 19.1.2.6, step 1 */
38837         if (duk_get_current_magic(thr) == 0) {
38838                 duk_to_object(thr, 0);
38839         }
38840
38841         /* [ obj key ] */
38842
38843         duk_hobject_object_get_own_property_descriptor(thr, -2);
38844         return 1;
38845 }
38846 #endif  /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
38847
38848 #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
38849 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_hthread *thr) {
38850         /*
38851          *  magic = 0: Object.isExtensible()
38852          *  magic = 1: Reflect.isExtensible()
38853          */
38854
38855         duk_hobject *h;
38856
38857         if (duk_get_current_magic(thr) == 0) {
38858                 h = duk_get_hobject(thr, 0);
38859         } else {
38860                 /* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs
38861                  * and plain buffers here because they pretend to be objects.
38862                  */
38863                 h = duk_require_hobject_accept_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
38864         }
38865
38866         duk_push_boolean(thr, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h));
38867         return 1;
38868 }
38869 #endif  /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
38870
38871 #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
38872 /* Shared helper for various key/symbol listings, magic:
38873  * 0=Object.keys()
38874  * 1=Object.getOwnPropertyNames(),
38875  * 2=Object.getOwnPropertySymbols(),
38876  * 3=Reflect.ownKeys()
38877  */
38878 DUK_LOCAL const duk_small_uint_t duk__object_keys_enum_flags[4] = {
38879         /* Object.keys() */
38880         DUK_ENUM_OWN_PROPERTIES_ONLY |
38881             DUK_ENUM_NO_PROXY_BEHAVIOR,
38882
38883         /* Object.getOwnPropertyNames() */
38884         DUK_ENUM_INCLUDE_NONENUMERABLE |
38885             DUK_ENUM_OWN_PROPERTIES_ONLY |
38886             DUK_ENUM_NO_PROXY_BEHAVIOR,
38887
38888         /* Object.getOwnPropertySymbols() */
38889         DUK_ENUM_INCLUDE_SYMBOLS |
38890             DUK_ENUM_OWN_PROPERTIES_ONLY |
38891             DUK_ENUM_EXCLUDE_STRINGS |
38892             DUK_ENUM_INCLUDE_NONENUMERABLE |
38893             DUK_ENUM_NO_PROXY_BEHAVIOR,
38894
38895         /* Reflect.ownKeys() */
38896         DUK_ENUM_INCLUDE_SYMBOLS |
38897             DUK_ENUM_OWN_PROPERTIES_ONLY |
38898             DUK_ENUM_INCLUDE_NONENUMERABLE |
38899             DUK_ENUM_NO_PROXY_BEHAVIOR
38900 };
38901
38902 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_hthread *thr) {
38903         duk_hobject *obj;
38904 #if defined(DUK_USE_ES6_PROXY)
38905         duk_hobject *h_proxy_target;
38906         duk_hobject *h_proxy_handler;
38907         duk_hobject *h_trap_result;
38908 #endif
38909         duk_small_uint_t enum_flags;
38910         duk_int_t magic;
38911
38912         DUK_ASSERT_TOP(thr, 1);
38913
38914         magic = duk_get_current_magic(thr);
38915         if (magic == 3) {
38916                 /* ES2015 Section 26.1.11 requires a TypeError for non-objects.  Lightfuncs
38917                  * and plain buffers pretend to be objects, so accept those too.
38918                  */
38919                 obj = duk_require_hobject_promote_mask(thr, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
38920         } else {
38921                 /* ES2015: ToObject coerce. */
38922                 obj = duk_to_hobject(thr, 0);
38923         }
38924         DUK_ASSERT(obj != NULL);
38925         DUK_UNREF(obj);
38926
38927         /* XXX: proxy chains */
38928
38929 #if defined(DUK_USE_ES6_PROXY)
38930         /* XXX: better sharing of code between proxy target call sites */
38931         if (DUK_LIKELY(!duk_hobject_proxy_check(obj,
38932                                                 &h_proxy_target,
38933                                                 &h_proxy_handler))) {
38934                 goto skip_proxy;
38935         }
38936
38937         duk_push_hobject(thr, h_proxy_handler);
38938         if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
38939                 /* Careful with reachability here: don't pop 'obj' before pushing
38940                  * proxy target.
38941                  */
38942                 DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
38943                 duk_pop_2(thr);
38944                 duk_push_hobject(thr, h_proxy_target);
38945                 duk_replace(thr, 0);
38946                 DUK_ASSERT_TOP(thr, 1);
38947                 goto skip_proxy;
38948         }
38949
38950         /* [ obj handler trap ] */
38951         duk_insert(thr, -2);
38952         duk_push_hobject(thr, h_proxy_target);  /* -> [ obj trap handler target ] */
38953         duk_call_method(thr, 1 /*nargs*/);      /* -> [ obj trap_result ] */
38954         h_trap_result = duk_require_hobject(thr, -1);
38955         DUK_UNREF(h_trap_result);
38956
38957         magic = duk_get_current_magic(thr);
38958         DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
38959         enum_flags = duk__object_keys_enum_flags[magic];
38960
38961         duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
38962         return 1;
38963
38964  skip_proxy:
38965 #endif  /* DUK_USE_ES6_PROXY */
38966
38967         DUK_ASSERT_TOP(thr, 1);
38968         magic = duk_get_current_magic(thr);
38969         DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
38970         enum_flags = duk__object_keys_enum_flags[magic];
38971         return duk_hobject_get_enumerated_keys(thr, enum_flags);
38972 }
38973 #endif  /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
38974
38975 #if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
38976 DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_hthread *thr) {
38977         /*
38978          *  magic = 0: Object.preventExtensions()
38979          *  magic = 1: Reflect.preventExtensions()
38980          */
38981
38982         duk_hobject *h;
38983         duk_uint_t mask;
38984         duk_int_t magic;
38985
38986         magic = duk_get_current_magic(thr);
38987
38988         /* Silent success for lightfuncs and plain buffers always. */
38989         mask = DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER;
38990
38991         /* Object.preventExtensions() silent success for non-object. */
38992         if (magic == 0) {
38993                 mask |= DUK_TYPE_MASK_UNDEFINED |
38994                         DUK_TYPE_MASK_NULL |
38995                         DUK_TYPE_MASK_BOOLEAN |
38996                         DUK_TYPE_MASK_NUMBER |
38997                         DUK_TYPE_MASK_STRING |
38998                         DUK_TYPE_MASK_POINTER;
38999         }
39000
39001         if (duk_check_type_mask(thr, 0, mask)) {
39002                 /* Not an object, already non-extensible so always success. */
39003                 goto done;
39004         }
39005         h = duk_require_hobject(thr, 0);
39006         DUK_ASSERT(h != NULL);
39007
39008         DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
39009
39010         /* A non-extensible object cannot gain any more properties,
39011          * so this is a good time to compact.
39012          */
39013         duk_hobject_compact_props(thr, h);
39014
39015  done:
39016         if (magic == 1) {
39017                 duk_push_true(thr);
39018         }
39019         return 1;
39020 }
39021 #endif  /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
39022
39023 /*
39024  *  __defineGetter__, __defineSetter__, __lookupGetter__, __lookupSetter__
39025  */
39026
39027 #if defined(DUK_USE_ES8)
39028 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_defineaccessor(duk_hthread *thr) {
39029         duk_push_this(thr);
39030         duk_insert(thr, 0);
39031         duk_to_object(thr, 0);
39032         duk_require_callable(thr, 2);
39033
39034         /* [ ToObject(this) key getter/setter ] */
39035
39036         /* ToPropertyKey() coercion is not needed, duk_def_prop() does it. */
39037         duk_def_prop(thr, 0, DUK_DEFPROP_SET_ENUMERABLE |
39038                              DUK_DEFPROP_SET_CONFIGURABLE |
39039                              (duk_get_current_magic(thr) ? DUK_DEFPROP_HAVE_SETTER : DUK_DEFPROP_HAVE_GETTER));
39040         return 0;
39041 }
39042 DUK_INTERNAL duk_ret_t duk_bi_object_prototype_lookupaccessor(duk_hthread *thr) {
39043         duk_uint_t sanity;
39044
39045         duk_push_this(thr);
39046         duk_to_object(thr, -1);
39047
39048         /* XXX: Prototype walk (with sanity) should be a core property
39049          * operation, could add a flag to e.g. duk_get_prop_desc().
39050          */
39051
39052         /* ToPropertyKey() coercion is not needed, duk_get_prop_desc() does it. */
39053         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
39054         while (!duk_is_undefined(thr, -1)) {
39055                 /* [ key obj ] */
39056                 duk_dup(thr, 0);
39057                 duk_get_prop_desc(thr, 1, 0 /*flags*/);
39058                 if (!duk_is_undefined(thr, -1)) {
39059                         duk_get_prop_stridx(thr, -1, (duk_get_current_magic(thr) != 0 ? DUK_STRIDX_SET : DUK_STRIDX_GET));
39060                         return 1;
39061                 }
39062                 duk_pop(thr);
39063
39064                 if (DUK_UNLIKELY(sanity-- == 0)) {
39065                         DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
39066                         DUK_WO_NORETURN(return 0;);
39067                 }
39068
39069                 duk_get_prototype(thr, -1);
39070                 duk_remove(thr, -2);
39071         }
39072         return 1;
39073 }
39074 #endif  /* DUK_USE_ES8 */
39075 #line 1 "duk_bi_performance.c"
39076 /*
39077  *  High resolution time API (performance.now() et al)
39078  *
39079  *  API specification: https://encoding.spec.whatwg.org/#ap://www.w3.org/TR/hr-time/
39080  */
39081
39082 /* #include duk_internal.h -> already included */
39083
39084 #if defined(DUK_USE_PERFORMANCE_BUILTIN)
39085 DUK_INTERNAL duk_ret_t duk_bi_performance_now(duk_hthread *thr) {
39086         /* From API spec:
39087          * The DOMHighResTimeStamp type is used to store a time value in
39088          * milliseconds, measured relative from the time origin, global
39089          * monotonic clock, or a time value that represents a duration
39090          * between two DOMHighResTimeStamp's.
39091          */
39092         duk_push_number(thr, duk_time_get_monotonic_time(thr));
39093         return 1;
39094 }
39095
39096 #if 0  /* Missing until semantics decided. */
39097 DUK_INTERNAL duk_ret_t duk_bi_performance_timeorigin_getter(duk_hthread *thr) {
39098         /* No decision yet how to handle timeOrigins, e.g. should one be
39099          * initialized per heap, or per global object set.  See
39100          * https://www.w3.org/TR/hr-time/#time-origin.
39101          */
39102         duk_push_uint(thr, 0);
39103         return 1;
39104 }
39105 #endif  /* 0 */
39106 #endif  /* DUK_USE_PERFORMANCE_BUILTIN */
39107 #line 1 "duk_bi_pointer.c"
39108 /*
39109  *  Pointer built-ins
39110  */
39111
39112 /* #include duk_internal.h -> already included */
39113
39114 /*
39115  *  Constructor
39116  */
39117
39118 DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_hthread *thr) {
39119         /* XXX: this behavior is quite useless now; it would be nice to be able
39120          * to create pointer values from e.g. numbers or strings.  Numbers are
39121          * problematic on 64-bit platforms though.  Hex encoded strings?
39122          */
39123         if (duk_get_top(thr) == 0) {
39124                 duk_push_pointer(thr, NULL);
39125         } else {
39126                 duk_to_pointer(thr, 0);
39127         }
39128         DUK_ASSERT(duk_is_pointer(thr, 0));
39129         duk_set_top(thr, 1);
39130
39131         if (duk_is_constructor_call(thr)) {
39132                 (void) duk_push_object_helper(thr,
39133                                               DUK_HOBJECT_FLAG_EXTENSIBLE |
39134                                               DUK_HOBJECT_FLAG_FASTREFS |
39135                                               DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
39136                                               DUK_BIDX_POINTER_PROTOTYPE);
39137
39138                 /* Pointer object internal value is immutable */
39139                 duk_dup_0(thr);
39140                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
39141         }
39142         /* Note: unbalanced stack on purpose */
39143
39144         return 1;
39145 }
39146
39147 /*
39148  *  toString(), valueOf()
39149  */
39150
39151 DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_hthread *thr) {
39152         duk_tval *tv;
39153         duk_small_int_t to_string = duk_get_current_magic(thr);
39154
39155         duk_push_this(thr);
39156         tv = duk_require_tval(thr, -1);
39157         DUK_ASSERT(tv != NULL);
39158
39159         if (DUK_TVAL_IS_POINTER(tv)) {
39160                 /* nop */
39161         } else if (DUK_TVAL_IS_OBJECT(tv)) {
39162                 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
39163                 DUK_ASSERT(h != NULL);
39164
39165                 /* Must be a "pointer object", i.e. class "Pointer" */
39166                 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) {
39167                         goto type_error;
39168                 }
39169
39170                 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
39171         } else {
39172                 goto type_error;
39173         }
39174
39175         if (to_string) {
39176                 duk_to_string(thr, -1);
39177         }
39178         return 1;
39179
39180  type_error:
39181         DUK_DCERROR_TYPE_INVALID_ARGS(thr);
39182 }
39183 #line 1 "duk_bi_promise.c"
39184 /*
39185  *  Promise built-in
39186  */
39187
39188 /* #include duk_internal.h -> already included */
39189
39190 #if defined(DUK_USE_PROMISE_BUILTIN)
39191
39192 DUK_INTERNAL duk_ret_t duk_bi_promise_constructor(duk_hthread *thr) {
39193         DUK_ERROR_TYPE(thr, "unimplemented");
39194         DUK_WO_NORETURN(return 0;);
39195 }
39196
39197 DUK_INTERNAL duk_ret_t duk_bi_promise_all(duk_hthread *thr) {
39198         DUK_ERROR_TYPE(thr, "unimplemented");
39199         DUK_WO_NORETURN(return 0;);
39200 }
39201
39202 DUK_INTERNAL duk_ret_t duk_bi_promise_race(duk_hthread *thr) {
39203         DUK_ERROR_TYPE(thr, "unimplemented");
39204         DUK_WO_NORETURN(return 0;);
39205 }
39206
39207 DUK_INTERNAL duk_ret_t duk_bi_promise_reject(duk_hthread *thr) {
39208         DUK_ERROR_TYPE(thr, "unimplemented");
39209         DUK_WO_NORETURN(return 0;);
39210 }
39211
39212 DUK_INTERNAL duk_ret_t duk_bi_promise_resolve(duk_hthread *thr) {
39213         DUK_ERROR_TYPE(thr, "unimplemented");
39214         DUK_WO_NORETURN(return 0;);
39215 }
39216
39217 DUK_INTERNAL duk_ret_t duk_bi_promise_catch(duk_hthread *thr) {
39218         DUK_ERROR_TYPE(thr, "unimplemented");
39219         DUK_WO_NORETURN(return 0;);
39220 }
39221
39222 DUK_INTERNAL duk_ret_t duk_bi_promise_then(duk_hthread *thr) {
39223         DUK_ERROR_TYPE(thr, "unimplemented");
39224         DUK_WO_NORETURN(return 0;);
39225 }
39226
39227 #endif  /* DUK_USE_PROMISE_BUILTIN */
39228 #line 1 "duk_bi_proxy.c"
39229 /*
39230  *  Proxy built-in (ES2015)
39231  */
39232
39233 /* #include duk_internal.h -> already included */
39234
39235 #if defined(DUK_USE_ES6_PROXY)
39236 /* Post-process a Proxy ownKeys() result at stack top.  Push a cleaned up
39237  * array of valid result keys (strings or symbols).  TypeError for invalid
39238  * values.  Flags are shared with duk_enum().
39239  */
39240 DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_hthread *thr, duk_hobject *h_proxy_target, duk_uint_t flags) {
39241         duk_uarridx_t i, len, idx;
39242         duk_propdesc desc;
39243
39244         DUK_ASSERT_CTX_VALID(thr);
39245         DUK_ASSERT(h_proxy_target != NULL);
39246
39247         len = (duk_uarridx_t) duk_get_length(thr, -1);
39248         idx = 0;
39249         duk_push_array(thr);
39250         /* XXX: preallocated dense array, fill in directly */
39251         for (i = 0; i < len; i++) {
39252                 duk_hstring *h;
39253
39254                 /* [ obj trap_result res_arr ] */
39255                 (void) duk_get_prop_index(thr, -2, i);
39256                 h = duk_get_hstring(thr, -1);
39257                 if (h == NULL) {
39258                         DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
39259                         DUK_WO_NORETURN(return;);
39260                 }
39261
39262                 if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
39263                         /* No support for 'getOwnPropertyDescriptor' trap yet,
39264                          * so check enumerability always from target object
39265                          * descriptor.
39266                          */
39267                         if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(thr, -1), &desc, 0 /*flags*/)) {
39268                                 if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
39269                                         DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(thr, -1)));
39270                                         goto skip_key;
39271                                 }
39272                         } else {
39273                                 DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(thr, -1)));
39274                                 goto skip_key;
39275                         }
39276                 }
39277                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
39278                         if (!(flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
39279                                 DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(thr, -1)));
39280                                 goto skip_key;
39281                         }
39282                         if (DUK_HSTRING_HAS_HIDDEN(h) && !(flags & DUK_ENUM_INCLUDE_HIDDEN)) {
39283                                 DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(thr, -1)));
39284                                 goto skip_key;
39285                         }
39286                 } else {
39287                         if (flags & DUK_ENUM_EXCLUDE_STRINGS) {
39288                                 DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(thr, -1)));
39289                                 goto skip_key;
39290                         }
39291                 }
39292
39293                 /* [ obj trap_result res_arr propname ] */
39294                 duk_put_prop_index(thr, -2, idx++);
39295                 continue;
39296
39297          skip_key:
39298                 duk_pop(thr);
39299                 continue;
39300         }
39301
39302         /* XXX: Missing trap result validation for non-configurable target keys
39303          * (must be present), for non-extensible target all target keys must be
39304          * present and no extra keys can be present.
39305          * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
39306          */
39307
39308         /* XXX: The key enumerability check should trigger the "getOwnPropertyDescriptor"
39309          * trap which has not yet been implemented.  In the absence of such a trap,
39310          * the enumerability should be checked from the target object; this is
39311          * handled above.
39312          */
39313 }
39314 #endif  /* DUK_USE_ES6_PROXY */
39315
39316 #if defined(DUK_USE_ES6_PROXY)
39317 DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_hthread *thr) {
39318         DUK_ASSERT_TOP(thr, 2);  /* [ target handler ] */
39319
39320         duk_require_constructor_call(thr);
39321         duk_push_proxy(thr, 0 /*flags*/);  /* [ target handler ] -> [ proxy ] */
39322         return 1;  /* replacement */
39323 }
39324 #endif  /* DUK_USE_ES6_PROXY */
39325 #line 1 "duk_bi_reflect.c"
39326 /*
39327  *  'Reflect' built-in (ES2016 Section 26.1)
39328  *  http://www.ecma-international.org/ecma-262/7.0/#sec-reflect-object
39329  *
39330  *  Many Reflect built-in functions are provided by shared helpers in
39331  *  duk_bi_object.c or duk_bi_function.c.
39332  */
39333
39334 /* #include duk_internal.h -> already included */
39335
39336 #if defined(DUK_USE_REFLECT_BUILTIN)
39337 DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_hthread *thr) {
39338         duk_tval *tv_obj;
39339         duk_tval *tv_key;
39340         duk_bool_t ret;
39341
39342         DUK_ASSERT_TOP(thr, 2);
39343         (void) duk_require_hobject(thr, 0);
39344         (void) duk_to_string(thr, 1);
39345
39346         /* [ target key ] */
39347
39348         DUK_ASSERT(thr != NULL);
39349         tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
39350         tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
39351         ret = duk_hobject_delprop(thr, tv_obj, tv_key, 0 /*throw_flag*/);
39352         duk_push_boolean(thr, ret);
39353         return 1;
39354 }
39355
39356 DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_hthread *thr) {
39357         duk_tval *tv_obj;
39358         duk_tval *tv_key;
39359         duk_idx_t nargs;
39360
39361         DUK_ASSERT(thr != NULL);
39362         nargs = duk_get_top_require_min(thr, 2 /*min_top*/);
39363         (void) duk_require_hobject(thr, 0);
39364         (void) duk_to_string(thr, 1);
39365         if (nargs >= 3 && !duk_strict_equals(thr, 0, 2)) {
39366                 /* XXX: [[Get]] receiver currently unsupported */
39367                 DUK_ERROR_UNSUPPORTED(thr);
39368                 DUK_WO_NORETURN(return 0;);
39369         }
39370
39371         /* [ target key receiver? ...? ] */
39372
39373         tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
39374         tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
39375         (void) duk_hobject_getprop(thr, tv_obj, tv_key);  /* This could also be a duk_get_prop(). */
39376         return 1;
39377 }
39378
39379 DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_hthread *thr) {
39380         duk_tval *tv_obj;
39381         duk_tval *tv_key;
39382         duk_bool_t ret;
39383
39384         DUK_ASSERT(thr != NULL);
39385         DUK_ASSERT_TOP(thr, 2);
39386         (void) duk_require_hobject(thr, 0);
39387         (void) duk_to_string(thr, 1);
39388
39389         /* [ target key ] */
39390
39391         tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
39392         tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
39393         ret = duk_hobject_hasprop(thr, tv_obj, tv_key);
39394         duk_push_boolean(thr, ret);
39395         return 1;
39396 }
39397
39398 DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_hthread *thr) {
39399         duk_tval *tv_obj;
39400         duk_tval *tv_key;
39401         duk_tval *tv_val;
39402         duk_idx_t nargs;
39403         duk_bool_t ret;
39404
39405         DUK_ASSERT(thr != NULL);
39406         nargs = duk_get_top_require_min(thr, 3 /*min_top*/);
39407         (void) duk_require_hobject(thr, 0);
39408         (void) duk_to_string(thr, 1);
39409         if (nargs >= 4 && !duk_strict_equals(thr, 0, 3)) {
39410                 /* XXX: [[Set]] receiver currently unsupported */
39411                 DUK_ERROR_UNSUPPORTED(thr);
39412                 DUK_WO_NORETURN(return 0;);
39413         }
39414
39415         /* [ target key value receiver? ...? ] */
39416
39417         tv_obj = DUK_GET_TVAL_POSIDX(thr, 0);
39418         tv_key = DUK_GET_TVAL_POSIDX(thr, 1);
39419         tv_val = DUK_GET_TVAL_POSIDX(thr, 2);
39420         ret = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, 0 /*throw_flag*/);
39421         duk_push_boolean(thr, ret);
39422         return 1;
39423 }
39424 #endif  /* DUK_USE_REFLECT_BUILTIN */
39425 #line 1 "duk_bi_regexp.c"
39426 /*
39427  *  RegExp built-ins
39428  */
39429
39430 /* #include duk_internal.h -> already included */
39431
39432 #if defined(DUK_USE_REGEXP_SUPPORT)
39433
39434 DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) {
39435         duk_hobject *h;
39436
39437         duk_push_this(thr);
39438         h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP);
39439         DUK_ASSERT(h != NULL);
39440         DUK_UNREF(h);
39441         duk_insert(thr, 0);  /* prepend regexp to valstack 0 index */
39442 }
39443
39444 /* XXX: much to improve (code size) */
39445 DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_hthread *thr) {
39446         duk_hobject *h_pattern;
39447
39448         DUK_ASSERT_TOP(thr, 2);
39449         h_pattern = duk_get_hobject(thr, 0);
39450
39451         if (!duk_is_constructor_call(thr) &&
39452             h_pattern != NULL &&
39453             DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
39454             duk_is_undefined(thr, 1)) {
39455                 /* Called as a function, pattern has [[Class]] "RegExp" and
39456                  * flags is undefined -> return object as is.
39457                  */
39458                 /* XXX: ES2015 has a NewTarget SameValue() check which is not
39459                  * yet implemented.
39460                  */
39461                 duk_dup_0(thr);
39462                 return 1;
39463         }
39464
39465         /* Else functionality is identical for function call and constructor
39466          * call.
39467          */
39468
39469         if (h_pattern != NULL &&
39470             DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
39471                 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_SOURCE);
39472                 if (duk_is_undefined(thr, 1)) {
39473                         /* In ES5 one would need to read the flags individually;
39474                          * in ES2015 just read .flags.
39475                          */
39476                         duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
39477                 } else {
39478                         /* In ES2015 allowed; overrides argument RegExp flags. */
39479                         duk_dup_1(thr);
39480                 }
39481         } else {
39482                 if (duk_is_undefined(thr, 0)) {
39483                         duk_push_hstring_empty(thr);
39484                 } else {
39485                         duk_dup_0(thr);
39486                         duk_to_string(thr, -1);  /* Rejects Symbols. */
39487                 }
39488                 if (duk_is_undefined(thr, 1)) {
39489                         duk_push_hstring_empty(thr);
39490                 } else {
39491                         duk_dup_1(thr);
39492                         duk_to_string(thr, -1);  /* Rejects Symbols. */
39493                 }
39494
39495                 /* [ ... pattern flags ] */
39496         }
39497
39498         DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
39499                              (duk_tval *) duk_get_tval(thr, -2), (duk_tval *) duk_get_tval(thr, -1)));
39500
39501         /* [ ... pattern flags ] (both uncoerced) */
39502
39503         duk_to_string(thr, -2);
39504         duk_to_string(thr, -1);
39505         duk_regexp_compile(thr);
39506
39507         /* [ ... bytecode escaped_source ] */
39508
39509         duk_regexp_create_instance(thr);
39510
39511         /* [ ... RegExp ] */
39512
39513         return 1;
39514 }
39515
39516 DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_hthread *thr) {
39517         duk__get_this_regexp(thr);
39518
39519         /* [ regexp input ] */
39520
39521         duk_regexp_match(thr);
39522
39523         /* [ result ] */
39524
39525         return 1;
39526 }
39527
39528 DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_hthread *thr) {
39529         duk__get_this_regexp(thr);
39530
39531         /* [ regexp input ] */
39532
39533         /* result object is created and discarded; wasteful but saves code space */
39534         duk_regexp_match(thr);
39535
39536         /* [ result ] */
39537
39538         duk_push_boolean(thr, (duk_is_null(thr, -1) ? 0 : 1));
39539
39540         return 1;
39541 }
39542
39543 DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_hthread *thr) {
39544         /* This must be generic in ES2015 and later. */
39545         DUK_ASSERT_TOP(thr, 0);
39546         duk_push_this(thr);
39547         duk_push_literal(thr, "/");
39548         duk_get_prop_stridx(thr, 0, DUK_STRIDX_SOURCE);
39549         duk_dup_m2(thr);  /* another "/" */
39550         duk_get_prop_stridx(thr, 0, DUK_STRIDX_FLAGS);
39551         duk_concat(thr, 4);
39552         return 1;
39553 }
39554
39555 DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_hthread *thr) {
39556         /* .flags is ES2015 but present even when ES2015 bindings are
39557          * disabled because the constructor relies on it.
39558          */
39559         duk_uint8_t buf[8];  /* enough for all flags + NUL */
39560         duk_uint8_t *p = buf;
39561
39562         /* .flags is generic and works on any object. */
39563         duk_push_this(thr);
39564         (void) duk_require_hobject(thr, -1);
39565         if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL)) {
39566                 *p++ = DUK_ASC_LC_G;
39567         }
39568         if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_IGNORE_CASE, NULL)) {
39569                 *p++ = DUK_ASC_LC_I;
39570         }
39571         if (duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_MULTILINE, NULL)) {
39572                 *p++ = DUK_ASC_LC_M;
39573         }
39574         /* .unicode: to be added */
39575         /* .sticky: to be added */
39576         *p++ = DUK_ASC_NUL;
39577         DUK_ASSERT((duk_size_t) (p - buf) <= sizeof(buf));
39578
39579         duk_push_string(thr, (const char *) buf);
39580         return 1;
39581 }
39582
39583 /* Shared helper for providing .source, .global, .multiline, etc getters. */
39584 DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_hthread *thr) {
39585         duk_hstring *h_bc;
39586         duk_small_uint_t re_flags;
39587         duk_hobject *h;
39588         duk_int_t magic;
39589
39590         DUK_ASSERT_TOP(thr, 0);
39591
39592         duk_push_this(thr);
39593         h = duk_require_hobject(thr, -1);
39594         magic = duk_get_current_magic(thr);
39595
39596         if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_REGEXP) {
39597                 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_INT_SOURCE);
39598                 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_INT_BYTECODE);
39599                 h_bc = duk_require_hstring(thr, -1);
39600                 re_flags = (duk_small_uint_t) DUK_HSTRING_GET_DATA(h_bc)[0];  /* Safe even if h_bc length is 0 (= NUL) */
39601                 duk_pop(thr);
39602         } else if (h == thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]) {
39603                 /* In ES2015 and ES2016 a TypeError would be thrown here.
39604                  * However, this had real world issues so ES2017 draft
39605                  * allows RegExp.prototype specifically, returning '(?:)'
39606                  * for .source and undefined for all flags.
39607                  */
39608                 if (magic != 16 /* .source */) {
39609                         return 0;
39610                 }
39611                 duk_push_literal(thr, "(?:)");  /* .source handled by switch-case */
39612                 re_flags = 0;
39613         } else {
39614                 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
39615         }
39616
39617         /* [ regexp source ] */
39618
39619         switch (magic) {
39620         case 0: {  /* global */
39621                 duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_GLOBAL));
39622                 break;
39623         }
39624         case 1: {  /* ignoreCase */
39625                 duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
39626                 break;
39627         }
39628         case 2: {  /* multiline */
39629                 duk_push_boolean(thr, (re_flags & DUK_RE_FLAG_MULTILINE));
39630                 break;
39631         }
39632 #if 0
39633         /* Don't provide until implemented to avoid interfering with feature
39634          * detection in user code.
39635          */
39636         case 3:    /* sticky */
39637         case 4: {  /* unicode */
39638                 duk_push_false(thr);
39639                 break;
39640         }
39641 #endif
39642         default: {  /* source */
39643                 /* leave 'source' on top */
39644                 break;
39645         }
39646         }
39647
39648         return 1;
39649 }
39650
39651 #endif  /* DUK_USE_REGEXP_SUPPORT */
39652 #line 1 "duk_bi_string.c"
39653 /*
39654  *  String built-ins
39655  *
39656  *  Most String built-ins must only accept strings (or String objects).
39657  *  Symbols, represented internally as strings, must be generally rejected.
39658  *  The duk_push_this_coercible_to_string() helper does this automatically.
39659  */
39660
39661 /* XXX: There are several limitations in the current implementation for
39662  * strings with >= 0x80000000UL characters.  In some cases one would need
39663  * to be able to represent the range [-0xffffffff,0xffffffff] and so on.
39664  * Generally character and byte length are assumed to fit into signed 32
39665  * bits (< 0x80000000UL).  Places with issues are not marked explicitly
39666  * below in all cases, look for signed type usage (duk_int_t etc) for
39667  * offsets/lengths.
39668  */
39669
39670 /* #include duk_internal.h -> already included */
39671
39672 #if defined(DUK_USE_STRING_BUILTIN)
39673
39674 /*
39675  *  Helpers
39676  */
39677
39678 DUK_LOCAL duk_hstring *duk__str_tostring_notregexp(duk_hthread *thr, duk_idx_t idx) {
39679         duk_hstring *h;
39680
39681         if (duk_get_class_number(thr, idx) == DUK_HOBJECT_CLASS_REGEXP) {
39682                 DUK_ERROR_TYPE_INVALID_ARGS(thr);
39683                 DUK_WO_NORETURN(return NULL;);
39684         }
39685         h = duk_to_hstring(thr, idx);
39686         DUK_ASSERT(h != NULL);
39687
39688         return h;
39689 }
39690
39691 DUK_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) {
39692         duk_int_t cpos;
39693         duk_int_t bpos;
39694         const duk_uint8_t *p_start, *p_end, *p;
39695         const duk_uint8_t *q_start;
39696         duk_int_t q_blen;
39697         duk_uint8_t firstbyte;
39698         duk_uint8_t t;
39699
39700         cpos = start_cpos;
39701
39702         /* Empty searchstring always matches; cpos must be clamped here.
39703          * (If q_blen were < 0 due to clamped coercion, it would also be
39704          * caught here.)
39705          */
39706         q_start = DUK_HSTRING_GET_DATA(h_search);
39707         q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search);
39708         if (q_blen <= 0) {
39709                 return cpos;
39710         }
39711         DUK_ASSERT(q_blen > 0);
39712
39713         bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
39714
39715         p_start = DUK_HSTRING_GET_DATA(h_this);
39716         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
39717         p = p_start + bpos;
39718
39719         /* This loop is optimized for size.  For speed, there should be
39720          * two separate loops, and we should ensure that memcmp() can be
39721          * used without an extra "will searchstring fit" check.  Doing
39722          * the preconditioning for 'p' and 'p_end' is easy but cpos
39723          * must be updated if 'p' is wound back (backward scanning).
39724          */
39725
39726         firstbyte = q_start[0];  /* leading byte of match string */
39727         while (p <= p_end && p >= p_start) {
39728                 t = *p;
39729
39730                 /* For ECMAScript strings, this check can only match for
39731                  * initial UTF-8 bytes (not continuation bytes).  For other
39732                  * strings all bets are off.
39733                  */
39734
39735                 if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
39736                         DUK_ASSERT(q_blen > 0);
39737                         if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
39738                                 return cpos;
39739                         }
39740                 }
39741
39742                 /* track cpos while scanning */
39743                 if (backwards) {
39744                         /* when going backwards, we decrement cpos 'early';
39745                          * 'p' may point to a continuation byte of the char
39746                          * at offset 'cpos', but that's OK because we'll
39747                          * backtrack all the way to the initial byte.
39748                          */
39749                         if ((t & 0xc0) != 0x80) {
39750                                 cpos--;
39751                         }
39752                         p--;
39753                 } else {
39754                         if ((t & 0xc0) != 0x80) {
39755                                 cpos++;
39756                         }
39757                         p++;
39758                 }
39759         }
39760
39761         /* Not found.  Empty string case is handled specially above. */
39762         return -1;
39763 }
39764
39765 /*
39766  *  Constructor
39767  */
39768
39769 DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_hthread *thr) {
39770         duk_hstring *h;
39771         duk_uint_t flags;
39772
39773         /* String constructor needs to distinguish between an argument not given at all
39774          * vs. given as 'undefined'.  We're a vararg function to handle this properly.
39775          */
39776
39777         /* XXX: copy current activation flags to thr, including current magic,
39778          * is_constructor_call etc.  This takes a few bytes in duk_hthread but
39779          * makes call sites smaller (there are >30 is_constructor_call and get
39780          * current magic call sites.
39781          */
39782
39783         if (duk_get_top(thr) == 0) {
39784                 duk_push_hstring_empty(thr);
39785         } else {
39786                 h = duk_to_hstring_acceptsymbol(thr, 0);
39787                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(thr))) {
39788                         duk_push_symbol_descriptive_string(thr, h);
39789                         duk_replace(thr, 0);
39790                 }
39791         }
39792         duk_to_string(thr, 0);  /* catches symbol argument for constructor call */
39793         DUK_ASSERT(duk_is_string(thr, 0));
39794         duk_set_top(thr, 1);  /* Top may be 1 or larger. */
39795
39796         if (duk_is_constructor_call(thr)) {
39797                 /* String object internal value is immutable */
39798                 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
39799                         DUK_HOBJECT_FLAG_FASTREFS |
39800                         DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
39801                         DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
39802                 duk_push_object_helper(thr, flags, DUK_BIDX_STRING_PROTOTYPE);
39803                 duk_dup_0(thr);
39804                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
39805         }
39806         /* Note: unbalanced stack on purpose */
39807
39808         return 1;
39809 }
39810
39811 DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_hthread *thr, duk_bool_t nonbmp) {
39812         duk_bufwriter_ctx bw_alloc;
39813         duk_bufwriter_ctx *bw;
39814         duk_idx_t i, n;
39815         duk_ucodepoint_t cp;
39816
39817         /* XXX: It would be nice to build the string directly but ToUint16()
39818          * coercion is needed so a generic helper would not be very
39819          * helpful (perhaps coerce the value stack first here and then
39820          * build a string from a duk_tval number sequence in one go?).
39821          */
39822
39823         n = duk_get_top(thr);
39824
39825         bw = &bw_alloc;
39826         DUK_BW_INIT_PUSHBUF(thr, bw, (duk_size_t) n);  /* initial estimate for ASCII only codepoints */
39827
39828         for (i = 0; i < n; i++) {
39829                 /* XXX: could improve bufwriter handling to write multiple codepoints
39830                  * with one ensure call but the relative benefit would be quite small.
39831                  */
39832
39833                 if (nonbmp) {
39834                         /* ES2015 requires that (1) SameValue(cp, ToInteger(cp)) and
39835                          * (2) cp >= 0 and cp <= 0x10ffff.  This check does not
39836                          * implement the steps exactly but the outcome should be
39837                          * the same.
39838                          */
39839                         duk_int32_t i32 = 0;
39840                         if (!duk_is_whole_get_int32(duk_to_number(thr, i), &i32) ||
39841                             i32 < 0 || i32 > 0x10ffffL) {
39842                                 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
39843                         }
39844                         DUK_ASSERT(i32 >= 0 && i32 <= 0x10ffffL);
39845                         cp = (duk_ucodepoint_t) i32;
39846                         DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
39847                 } else {
39848 #if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT)
39849                         /* ToUint16() coercion is mandatory in the E5.1 specification, but
39850                          * this non-compliant behavior makes more sense because we support
39851                          * non-BMP codepoints.  Don't use CESU-8 because that'd create
39852                          * surrogate pairs.
39853                          */
39854                         cp = (duk_ucodepoint_t) duk_to_uint32(thr, i);
39855                         DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
39856 #else
39857                         cp = (duk_ucodepoint_t) duk_to_uint16(thr, i);
39858                         DUK_ASSERT(cp >= 0 && cp <= 0x10ffffL);
39859                         DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
39860 #endif
39861                 }
39862         }
39863
39864         DUK_BW_COMPACT(thr, bw);
39865         (void) duk_buffer_to_string(thr, -1);  /* Safe, extended UTF-8 or CESU-8 encoded. */
39866         return 1;
39867 }
39868
39869 DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_hthread *thr) {
39870         return duk__construct_from_codepoints(thr, 0 /*nonbmp*/);
39871 }
39872
39873 #if defined(DUK_USE_ES6)
39874 DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_hthread *thr) {
39875         return duk__construct_from_codepoints(thr, 1 /*nonbmp*/);
39876 }
39877 #endif
39878
39879 /*
39880  *  toString(), valueOf()
39881  */
39882
39883 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_hthread *thr) {
39884         duk_tval *tv;
39885
39886         duk_push_this(thr);
39887         tv = duk_require_tval(thr, -1);
39888         DUK_ASSERT(tv != NULL);
39889
39890         if (DUK_TVAL_IS_STRING(tv)) {
39891                 /* return as is */
39892         } else if (DUK_TVAL_IS_OBJECT(tv)) {
39893                 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
39894                 DUK_ASSERT(h != NULL);
39895
39896                 /* Must be a "string object", i.e. class "String" */
39897                 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) {
39898                         goto type_error;
39899                 }
39900
39901                 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VALUE);
39902                 DUK_ASSERT(duk_is_string(thr, -1));
39903         } else {
39904                 goto type_error;
39905         }
39906
39907         (void) duk_require_hstring_notsymbol(thr, -1);  /* Reject symbols (and wrapped symbols). */
39908         return 1;
39909
39910  type_error:
39911         DUK_DCERROR_TYPE_INVALID_ARGS(thr);
39912 }
39913
39914 /*
39915  *  Character and charcode access
39916  */
39917
39918 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_hthread *thr) {
39919         duk_hstring *h;
39920         duk_int_t pos;
39921
39922         /* XXX: faster implementation */
39923
39924         h = duk_push_this_coercible_to_string(thr);
39925         DUK_ASSERT(h != NULL);
39926
39927         pos = duk_to_int(thr, 0);
39928
39929         if (sizeof(duk_size_t) >= sizeof(duk_uint_t)) {
39930                 /* Cast to duk_size_t works in this case:
39931                  * - If pos < 0, (duk_size_t) pos will always be
39932                  *   >= max_charlen, and result will be the empty string
39933                  *   (see duk_substring()).
39934                  * - If pos >= 0, pos + 1 cannot wrap.
39935                  */
39936                 DUK_ASSERT((duk_size_t) DUK_INT_MIN >= DUK_HSTRING_MAX_BYTELEN);
39937                 DUK_ASSERT((duk_size_t) DUK_INT_MAX + 1U > (duk_size_t) DUK_INT_MAX);
39938                 duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U);
39939         } else {
39940                 /* If size_t is smaller than int, explicit bounds checks
39941                  * are needed because an int may wrap multiple times.
39942                  */
39943                 if (DUK_UNLIKELY(pos < 0 || (duk_uint_t) pos >= (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h))) {
39944                         duk_push_hstring_empty(thr);
39945                 } else {
39946                         duk_substring(thr, -1, (duk_size_t) pos, (duk_size_t) pos + 1U);
39947                 }
39948         }
39949
39950         return 1;
39951 }
39952
39953 /* Magic: 0=charCodeAt, 1=codePointAt */
39954 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_hthread *thr) {
39955         duk_int_t pos;
39956         duk_hstring *h;
39957         duk_bool_t clamped;
39958         duk_uint32_t cp;
39959         duk_int_t magic;
39960
39961         /* XXX: faster implementation */
39962
39963         DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(thr, 0)));
39964
39965         h = duk_push_this_coercible_to_string(thr);
39966         DUK_ASSERT(h != NULL);
39967
39968         pos = duk_to_int_clamped_raw(thr,
39969                                      0 /*index*/,
39970                                      0 /*min(incl)*/,
39971                                      (duk_int_t) DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
39972                                      &clamped /*out_clamped*/);
39973 #if defined(DUK_USE_ES6)
39974         magic = duk_get_current_magic(thr);
39975 #else
39976         DUK_ASSERT(duk_get_current_magic(thr) == 0);
39977         magic = 0;
39978 #endif
39979         if (clamped) {
39980                 /* For out-of-bounds indices .charCodeAt() returns NaN and
39981                  * .codePointAt() returns undefined.
39982                  */
39983                 if (magic != 0) {
39984                         return 0;
39985                 }
39986                 duk_push_nan(thr);
39987         } else {
39988                 DUK_ASSERT(pos >= 0);
39989                 cp = (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) pos, (duk_bool_t) magic /*surrogate_aware*/);
39990                 duk_push_u32(thr, cp);
39991         }
39992         return 1;
39993 }
39994
39995 /*
39996  *  substring(), substr(), slice()
39997  */
39998
39999 /* XXX: any chance of merging these three similar but still slightly
40000  * different algorithms so that footprint would be reduced?
40001  */
40002
40003 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_hthread *thr) {
40004         duk_hstring *h;
40005         duk_int_t start_pos, end_pos;
40006         duk_int_t len;
40007
40008         h = duk_push_this_coercible_to_string(thr);
40009         DUK_ASSERT(h != NULL);
40010         len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
40011
40012         /* [ start end str ] */
40013
40014         start_pos = duk_to_int_clamped(thr, 0, 0, len);
40015         if (duk_is_undefined(thr, 1)) {
40016                 end_pos = len;
40017         } else {
40018                 end_pos = duk_to_int_clamped(thr, 1, 0, len);
40019         }
40020         DUK_ASSERT(start_pos >= 0 && start_pos <= len);
40021         DUK_ASSERT(end_pos >= 0 && end_pos <= len);
40022
40023         if (start_pos > end_pos) {
40024                 duk_int_t tmp = start_pos;
40025                 start_pos = end_pos;
40026                 end_pos = tmp;
40027         }
40028
40029         DUK_ASSERT(end_pos >= start_pos);
40030
40031         duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
40032         return 1;
40033 }
40034
40035 #if defined(DUK_USE_SECTION_B)
40036 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_hthread *thr) {
40037         duk_hstring *h;
40038         duk_int_t start_pos, end_pos;
40039         duk_int_t len;
40040
40041         /* Unlike non-obsolete String calls, substr() algorithm in E5.1
40042          * specification will happily coerce undefined and null to strings
40043          * ("undefined" and "null").
40044          */
40045         duk_push_this(thr);
40046         h = duk_to_hstring_m1(thr);  /* Reject Symbols. */
40047         DUK_ASSERT(h != NULL);
40048         len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
40049
40050         /* [ start length str ] */
40051
40052         /* The implementation for computing of start_pos and end_pos differs
40053          * from the standard algorithm, but is intended to result in the exactly
40054          * same behavior.  This is not always obvious.
40055          */
40056
40057         /* combines steps 2 and 5; -len ensures max() not needed for step 5 */
40058         start_pos = duk_to_int_clamped(thr, 0, -len, len);
40059         if (start_pos < 0) {
40060                 start_pos = len + start_pos;
40061         }
40062         DUK_ASSERT(start_pos >= 0 && start_pos <= len);
40063
40064         /* combines steps 3, 6; step 7 is not needed */
40065         if (duk_is_undefined(thr, 1)) {
40066                 end_pos = len;
40067         } else {
40068                 DUK_ASSERT(start_pos <= len);
40069                 end_pos = start_pos + duk_to_int_clamped(thr, 1, 0, len - start_pos);
40070         }
40071         DUK_ASSERT(start_pos >= 0 && start_pos <= len);
40072         DUK_ASSERT(end_pos >= 0 && end_pos <= len);
40073         DUK_ASSERT(end_pos >= start_pos);
40074
40075         duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
40076         return 1;
40077 }
40078 #endif  /* DUK_USE_SECTION_B */
40079
40080 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_hthread *thr) {
40081         duk_hstring *h;
40082         duk_int_t start_pos, end_pos;
40083         duk_int_t len;
40084
40085         h = duk_push_this_coercible_to_string(thr);
40086         DUK_ASSERT(h != NULL);
40087         len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
40088
40089         /* [ start end str ] */
40090
40091         start_pos = duk_to_int_clamped(thr, 0, -len, len);
40092         if (start_pos < 0) {
40093                 start_pos = len + start_pos;
40094         }
40095         if (duk_is_undefined(thr, 1)) {
40096                 end_pos = len;
40097         } else {
40098                 end_pos = duk_to_int_clamped(thr, 1, -len, len);
40099                 if (end_pos < 0) {
40100                         end_pos = len + end_pos;
40101                 }
40102         }
40103         DUK_ASSERT(start_pos >= 0 && start_pos <= len);
40104         DUK_ASSERT(end_pos >= 0 && end_pos <= len);
40105
40106         if (end_pos < start_pos) {
40107                 end_pos = start_pos;
40108         }
40109
40110         DUK_ASSERT(end_pos >= start_pos);
40111
40112         duk_substring(thr, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
40113         return 1;
40114 }
40115
40116 /*
40117  *  Case conversion
40118  */
40119
40120 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_hthread *thr) {
40121         duk_small_int_t uppercase = duk_get_current_magic(thr);
40122
40123         (void) duk_push_this_coercible_to_string(thr);
40124         duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase);
40125         return 1;
40126 }
40127
40128 /*
40129  *  indexOf() and lastIndexOf()
40130  */
40131
40132 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_hthread *thr) {
40133         duk_hstring *h_this;
40134         duk_hstring *h_search;
40135         duk_int_t clen_this;
40136         duk_int_t cpos;
40137         duk_small_uint_t is_lastindexof = (duk_small_uint_t) duk_get_current_magic(thr);  /* 0=indexOf, 1=lastIndexOf */
40138
40139         h_this = duk_push_this_coercible_to_string(thr);
40140         DUK_ASSERT(h_this != NULL);
40141         clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
40142
40143         h_search = duk_to_hstring(thr, 0);
40144         DUK_ASSERT(h_search != NULL);
40145
40146         duk_to_number(thr, 1);
40147         if (duk_is_nan(thr, 1) && is_lastindexof) {
40148                 /* indexOf: NaN should cause pos to be zero.
40149                  * lastIndexOf: NaN should cause pos to be +Infinity
40150                  * (and later be clamped to len).
40151                  */
40152                 cpos = clen_this;
40153         } else {
40154                 cpos = duk_to_int_clamped(thr, 1, 0, clen_this);
40155         }
40156
40157         cpos = duk__str_search_shared(thr, h_this, h_search, cpos, is_lastindexof /*backwards*/);
40158         duk_push_int(thr, cpos);
40159         return 1;
40160 }
40161
40162 /*
40163  *  replace()
40164  */
40165
40166 /* XXX: the current implementation works but is quite clunky; it compiles
40167  * to almost 1,4kB of x86 code so it needs to be simplified (better approach,
40168  * shared helpers, etc).  Some ideas for refactoring:
40169  *
40170  * - a primitive to convert a string into a regexp matcher (reduces matching
40171  *   code at the cost of making matching much slower)
40172  * - use replace() as a basic helper for match() and split(), which are both
40173  *   much simpler
40174  * - API call to get_prop and to_boolean
40175  */
40176
40177 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_hthread *thr) {
40178         duk_hstring *h_input;
40179         duk_hstring *h_match;
40180         duk_hstring *h_search;
40181         duk_hobject *h_re;
40182         duk_bufwriter_ctx bw_alloc;
40183         duk_bufwriter_ctx *bw;
40184 #if defined(DUK_USE_REGEXP_SUPPORT)
40185         duk_bool_t is_regexp;
40186         duk_bool_t is_global;
40187 #endif
40188         duk_bool_t is_repl_func;
40189         duk_uint32_t match_start_coff, match_start_boff;
40190 #if defined(DUK_USE_REGEXP_SUPPORT)
40191         duk_int_t match_caps;
40192 #endif
40193         duk_uint32_t prev_match_end_boff;
40194         const duk_uint8_t *r_start, *r_end, *r;   /* repl string scan */
40195         duk_size_t tmp_sz;
40196
40197         DUK_ASSERT_TOP(thr, 2);
40198         h_input = duk_push_this_coercible_to_string(thr);
40199         DUK_ASSERT(h_input != NULL);
40200
40201         bw = &bw_alloc;
40202         DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));  /* input size is good output starting point */
40203
40204         DUK_ASSERT_TOP(thr, 4);
40205
40206         /* stack[0] = search value
40207          * stack[1] = replace value
40208          * stack[2] = input string
40209          * stack[3] = result buffer
40210          */
40211
40212         h_re = duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP);
40213         if (h_re) {
40214 #if defined(DUK_USE_REGEXP_SUPPORT)
40215                 is_regexp = 1;
40216                 is_global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL);
40217
40218                 if (is_global) {
40219                         /* start match from beginning */
40220                         duk_push_int(thr, 0);
40221                         duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
40222                 }
40223 #else  /* DUK_USE_REGEXP_SUPPORT */
40224                 DUK_DCERROR_UNSUPPORTED(thr);
40225 #endif  /* DUK_USE_REGEXP_SUPPORT */
40226         } else {
40227                 duk_to_string(thr, 0);  /* rejects symbols */
40228 #if defined(DUK_USE_REGEXP_SUPPORT)
40229                 is_regexp = 0;
40230                 is_global = 0;
40231 #endif
40232         }
40233
40234         if (duk_is_function(thr, 1)) {
40235                 is_repl_func = 1;
40236                 r_start = NULL;
40237                 r_end = NULL;
40238         } else {
40239                 duk_hstring *h_repl;
40240
40241                 is_repl_func = 0;
40242                 h_repl = duk_to_hstring(thr, 1);  /* reject symbols */
40243                 DUK_ASSERT(h_repl != NULL);
40244                 r_start = DUK_HSTRING_GET_DATA(h_repl);
40245                 r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
40246         }
40247
40248         prev_match_end_boff = 0;
40249
40250         for (;;) {
40251                 /*
40252                  *  If matching with a regexp:
40253                  *    - non-global RegExp: lastIndex not touched on a match, zeroed
40254                  *      on a non-match
40255                  *    - global RegExp: on match, lastIndex will be updated by regexp
40256                  *      executor to point to next char after the matching part (so that
40257                  *      characters in the matching part are not matched again)
40258                  *
40259                  *  If matching with a string:
40260                  *    - always non-global match, find first occurrence
40261                  *
40262                  *  We need:
40263                  *    - The character offset of start-of-match for the replacer function
40264                  *    - The byte offsets for start-of-match and end-of-match to implement
40265                  *      the replacement values $&, $`, and $', and to copy non-matching
40266                  *      input string portions (including header and trailer) verbatim.
40267                  *
40268                  *  NOTE: the E5.1 specification is a bit vague how the RegExp should
40269                  *  behave in the replacement process; e.g. is matching done first for
40270                  *  all matches (in the global RegExp case) before any replacer calls
40271                  *  are made?  See: test-bi-string-proto-replace.js for discussion.
40272                  */
40273
40274                 DUK_ASSERT_TOP(thr, 4);
40275
40276 #if defined(DUK_USE_REGEXP_SUPPORT)
40277                 if (is_regexp) {
40278                         duk_dup_0(thr);
40279                         duk_dup_2(thr);
40280                         duk_regexp_match(thr);  /* [ ... regexp input ] -> [ res_obj ] */
40281                         if (!duk_is_object(thr, -1)) {
40282                                 duk_pop(thr);
40283                                 break;
40284                         }
40285
40286                         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
40287                         DUK_ASSERT(duk_is_number(thr, -1));
40288                         match_start_coff = duk_get_uint(thr, -1);
40289                         duk_pop(thr);
40290
40291                         duk_get_prop_index(thr, -1, 0);
40292                         DUK_ASSERT(duk_is_string(thr, -1));
40293                         h_match = duk_known_hstring(thr, -1);
40294                         duk_pop(thr);  /* h_match is borrowed, remains reachable through match_obj */
40295
40296                         if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
40297                                 /* This should be equivalent to match() algorithm step 8.f.iii.2:
40298                                  * detect an empty match and allow it, but don't allow it twice.
40299                                  */
40300                                 duk_uint32_t last_index;
40301
40302                                 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
40303                                 last_index = (duk_uint32_t) duk_get_uint(thr, -1);
40304                                 DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
40305                                                      (long) last_index, (long) (last_index + 1)));
40306                                 duk_pop(thr);
40307                                 duk_push_uint(thr, (duk_uint_t) (last_index + 1));
40308                                 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
40309                         }
40310
40311                         DUK_ASSERT(duk_get_length(thr, -1) <= DUK_INT_MAX);  /* string limits */
40312                         match_caps = (duk_int_t) duk_get_length(thr, -1);
40313                 } else {
40314 #else  /* DUK_USE_REGEXP_SUPPORT */
40315                 {  /* unconditionally */
40316 #endif  /* DUK_USE_REGEXP_SUPPORT */
40317                         const duk_uint8_t *p_start, *p_end, *p;   /* input string scan */
40318                         const duk_uint8_t *q_start;               /* match string */
40319                         duk_size_t q_blen;
40320
40321 #if defined(DUK_USE_REGEXP_SUPPORT)
40322                         DUK_ASSERT(!is_global);  /* single match always */
40323 #endif
40324
40325                         p_start = DUK_HSTRING_GET_DATA(h_input);
40326                         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
40327                         p = p_start;
40328
40329                         h_search = duk_known_hstring(thr, 0);
40330                         q_start = DUK_HSTRING_GET_DATA(h_search);
40331                         q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
40332
40333                         p_end -= q_blen;  /* ensure full memcmp() fits in while */
40334
40335                         match_start_coff = 0;
40336
40337                         while (p <= p_end) {
40338                                 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
40339                                 if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
40340                                         duk_dup_0(thr);
40341                                         h_match = duk_known_hstring(thr, -1);
40342 #if defined(DUK_USE_REGEXP_SUPPORT)
40343                                         match_caps = 0;
40344 #endif
40345                                         goto found;
40346                                 }
40347
40348                                 /* track utf-8 non-continuation bytes */
40349                                 if ((p[0] & 0xc0) != 0x80) {
40350                                         match_start_coff++;
40351                                 }
40352                                 p++;
40353                         }
40354
40355                         /* not found */
40356                         break;
40357                 }
40358          found:
40359
40360                 /* stack[0] = search value
40361                  * stack[1] = replace value
40362                  * stack[2] = input string
40363                  * stack[3] = result buffer
40364                  * stack[4] = regexp match OR match string
40365                  */
40366
40367                 match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
40368
40369                 tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
40370                 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
40371
40372                 prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match);
40373
40374                 if (is_repl_func) {
40375                         duk_idx_t idx_args;
40376                         duk_hstring *h_repl;
40377
40378                         /* regexp res_obj is at index 4 */
40379
40380                         duk_dup_1(thr);
40381                         idx_args = duk_get_top(thr);
40382
40383 #if defined(DUK_USE_REGEXP_SUPPORT)
40384                         if (is_regexp) {
40385                                 duk_int_t idx;
40386                                 duk_require_stack(thr, match_caps + 2);
40387                                 for (idx = 0; idx < match_caps; idx++) {
40388                                         /* match followed by capture(s) */
40389                                         duk_get_prop_index(thr, 4, (duk_uarridx_t) idx);
40390                                 }
40391                         } else {
40392 #else  /* DUK_USE_REGEXP_SUPPORT */
40393                         {  /* unconditionally */
40394 #endif  /* DUK_USE_REGEXP_SUPPORT */
40395                                 /* match == search string, by definition */
40396                                 duk_dup_0(thr);
40397                         }
40398                         duk_push_uint(thr, (duk_uint_t) match_start_coff);
40399                         duk_dup_2(thr);
40400
40401                         /* [ ... replacer match [captures] match_char_offset input ] */
40402
40403                         duk_call(thr, duk_get_top(thr) - idx_args);
40404                         h_repl = duk_to_hstring_m1(thr);  /* -> [ ... repl_value ] */
40405                         DUK_ASSERT(h_repl != NULL);
40406
40407                         DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);
40408
40409                         duk_pop(thr);  /* repl_value */
40410                 } else {
40411                         r = r_start;
40412
40413                         while (r < r_end) {
40414                                 duk_int_t ch1;
40415                                 duk_int_t ch2;
40416 #if defined(DUK_USE_REGEXP_SUPPORT)
40417                                 duk_int_t ch3;
40418 #endif
40419                                 duk_size_t left;
40420
40421                                 ch1 = *r++;
40422                                 if (ch1 != DUK_ASC_DOLLAR) {
40423                                         goto repl_write;
40424                                 }
40425                                 DUK_ASSERT(r <= r_end);
40426                                 left = (duk_size_t) (r_end - r);
40427
40428                                 if (left <= 0) {
40429                                         goto repl_write;
40430                                 }
40431
40432                                 ch2 = r[0];
40433                                 switch (ch2) {
40434                                 case DUK_ASC_DOLLAR: {
40435                                         ch1 = (1 << 8) + DUK_ASC_DOLLAR;
40436                                         goto repl_write;
40437                                 }
40438                                 case DUK_ASC_AMP: {
40439                                         DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match);
40440                                         r++;
40441                                         continue;
40442                                 }
40443                                 case DUK_ASC_GRAVE: {
40444                                         tmp_sz = (duk_size_t) match_start_boff;
40445                                         DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz);
40446                                         r++;
40447                                         continue;
40448                                 }
40449                                 case DUK_ASC_SINGLEQUOTE: {
40450                                         duk_uint32_t match_end_boff;
40451
40452                                         /* Use match charlen instead of bytelen, just in case the input and
40453                                          * match codepoint encodings would have different lengths.
40454                                          */
40455                                         /* XXX: charlen computed here, and also in char2byte helper. */
40456                                         match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr,
40457                                                                                                            h_input,
40458                                                                                                            match_start_coff + (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_match));
40459
40460                                         tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
40461                                         DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
40462                                         r++;
40463                                         continue;
40464                                 }
40465                                 default: {
40466 #if defined(DUK_USE_REGEXP_SUPPORT)
40467                                         duk_int_t capnum, captmp, capadv;
40468                                         /* XXX: optional check, match_caps is zero if no regexp,
40469                                          * so dollar will be interpreted literally anyway.
40470                                          */
40471
40472                                         if (!is_regexp) {
40473                                                 goto repl_write;
40474                                         }
40475
40476                                         if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) {
40477                                                 goto repl_write;
40478                                         }
40479                                         capnum = ch2 - DUK_ASC_0;
40480                                         capadv = 1;
40481
40482                                         if (left >= 2) {
40483                                                 ch3 = r[1];
40484                                                 if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) {
40485                                                         captmp = capnum * 10 + (ch3 - DUK_ASC_0);
40486                                                         if (captmp < match_caps) {
40487                                                                 capnum = captmp;
40488                                                                 capadv = 2;
40489                                                         }
40490                                                 }
40491                                         }
40492
40493                                         if (capnum > 0 && capnum < match_caps) {
40494                                                 DUK_ASSERT(is_regexp != 0);  /* match_caps == 0 without regexps */
40495
40496                                                 /* regexp res_obj is at offset 4 */
40497                                                 duk_get_prop_index(thr, 4, (duk_uarridx_t) capnum);
40498                                                 if (duk_is_string(thr, -1)) {
40499                                                         duk_hstring *h_tmp_str;
40500
40501                                                         h_tmp_str = duk_known_hstring(thr, -1);
40502
40503                                                         DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
40504                                                 } else {
40505                                                         /* undefined -> skip (replaced with empty) */
40506                                                 }
40507                                                 duk_pop(thr);
40508                                                 r += capadv;
40509                                                 continue;
40510                                         } else {
40511                                                 goto repl_write;
40512                                         }
40513 #else  /* DUK_USE_REGEXP_SUPPORT */
40514                                         goto repl_write;  /* unconditionally */
40515 #endif  /* DUK_USE_REGEXP_SUPPORT */
40516                                 }  /* default case */
40517                                 }  /* switch (ch2) */
40518
40519                          repl_write:
40520                                 /* ch1 = (r_increment << 8) + byte */
40521
40522                                 DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff));
40523                                 r += ch1 >> 8;
40524                         }  /* while repl */
40525                 }  /* if (is_repl_func) */
40526
40527                 duk_pop(thr);  /* pop regexp res_obj or match string */
40528
40529 #if defined(DUK_USE_REGEXP_SUPPORT)
40530                 if (!is_global) {
40531 #else
40532                 {  /* unconditionally; is_global==0 */
40533 #endif
40534                         break;
40535                 }
40536         }
40537
40538         /* trailer */
40539         tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
40540         DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
40541
40542         DUK_ASSERT_TOP(thr, 4);
40543         DUK_BW_COMPACT(thr, bw);
40544         (void) duk_buffer_to_string(thr, -1);  /* Safe if inputs are safe. */
40545         return 1;
40546 }
40547
40548 /*
40549  *  split()
40550  */
40551
40552 /* XXX: very messy now, but works; clean up, remove unused variables (nomimally
40553  * used so compiler doesn't complain).
40554  */
40555
40556 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_hthread *thr) {
40557         duk_hstring *h_input;
40558         duk_hstring *h_sep;
40559         duk_uint32_t limit;
40560         duk_uint32_t arr_idx;
40561 #if defined(DUK_USE_REGEXP_SUPPORT)
40562         duk_bool_t is_regexp;
40563 #endif
40564         duk_bool_t matched;  /* set to 1 if any match exists (needed for empty input special case) */
40565         duk_uint32_t prev_match_end_coff, prev_match_end_boff;
40566         duk_uint32_t match_start_boff, match_start_coff;
40567         duk_uint32_t match_end_boff, match_end_coff;
40568
40569         h_input = duk_push_this_coercible_to_string(thr);
40570         DUK_ASSERT(h_input != NULL);
40571
40572         duk_push_array(thr);
40573
40574         if (duk_is_undefined(thr, 1)) {
40575                 limit = 0xffffffffUL;
40576         } else {
40577                 limit = duk_to_uint32(thr, 1);
40578         }
40579
40580         if (limit == 0) {
40581                 return 1;
40582         }
40583
40584         /* If the separator is a RegExp, make a "clone" of it.  The specification
40585          * algorithm calls [[Match]] directly for specific indices; we emulate this
40586          * by tweaking lastIndex and using a "force global" variant of duk_regexp_match()
40587          * which will use global-style matching even when the RegExp itself is non-global.
40588          */
40589
40590         if (duk_is_undefined(thr, 0)) {
40591                 /* The spec algorithm first does "R = ToString(separator)" before checking
40592                  * whether separator is undefined.  Since this is side effect free, we can
40593                  * skip the ToString() here.
40594                  */
40595                 duk_dup_2(thr);
40596                 duk_put_prop_index(thr, 3, 0);
40597                 return 1;
40598         } else if (duk_get_hobject_with_class(thr, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
40599 #if defined(DUK_USE_REGEXP_SUPPORT)
40600                 duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR);
40601                 duk_dup_0(thr);
40602                 duk_new(thr, 1);  /* [ ... RegExp val ] -> [ ... res ] */
40603                 duk_replace(thr, 0);
40604                 /* lastIndex is initialized to zero by new RegExp() */
40605                 is_regexp = 1;
40606 #else
40607                 DUK_DCERROR_UNSUPPORTED(thr);
40608 #endif
40609         } else {
40610                 duk_to_string(thr, 0);
40611 #if defined(DUK_USE_REGEXP_SUPPORT)
40612                 is_regexp = 0;
40613 #endif
40614         }
40615
40616         /* stack[0] = separator (string or regexp)
40617          * stack[1] = limit
40618          * stack[2] = input string
40619          * stack[3] = result array
40620          */
40621
40622         prev_match_end_boff = 0;
40623         prev_match_end_coff = 0;
40624         arr_idx = 0;
40625         matched = 0;
40626
40627         for (;;) {
40628                 /*
40629                  *  The specification uses RegExp [[Match]] to attempt match at specific
40630                  *  offsets.  We don't have such a primitive, so we use an actual RegExp
40631                  *  and tweak lastIndex.  Since the RegExp may be non-global, we use a
40632                  *  special variant which forces global-like behavior for matching.
40633                  */
40634
40635                 DUK_ASSERT_TOP(thr, 4);
40636
40637 #if defined(DUK_USE_REGEXP_SUPPORT)
40638                 if (is_regexp) {
40639                         duk_dup_0(thr);
40640                         duk_dup_2(thr);
40641                         duk_regexp_match_force_global(thr);  /* [ ... regexp input ] -> [ res_obj ] */
40642                         if (!duk_is_object(thr, -1)) {
40643                                 duk_pop(thr);
40644                                 break;
40645                         }
40646                         matched = 1;
40647
40648                         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
40649                         DUK_ASSERT(duk_is_number(thr, -1));
40650                         match_start_coff = duk_get_uint(thr, -1);
40651                         match_start_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
40652                         duk_pop(thr);
40653
40654                         if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
40655                                 /* don't allow an empty match at the end of the string */
40656                                 duk_pop(thr);
40657                                 break;
40658                         }
40659
40660                         duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
40661                         DUK_ASSERT(duk_is_number(thr, -1));
40662                         match_end_coff = duk_get_uint(thr, -1);
40663                         match_end_boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
40664                         duk_pop(thr);
40665
40666                         /* empty match -> bump and continue */
40667                         if (prev_match_end_boff == match_end_boff) {
40668                                 duk_push_uint(thr, (duk_uint_t) (match_end_coff + 1));
40669                                 duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
40670                                 duk_pop(thr);
40671                                 continue;
40672                         }
40673                 } else {
40674 #else  /* DUK_USE_REGEXP_SUPPORT */
40675                 {  /* unconditionally */
40676 #endif  /* DUK_USE_REGEXP_SUPPORT */
40677                         const duk_uint8_t *p_start, *p_end, *p;   /* input string scan */
40678                         const duk_uint8_t *q_start;               /* match string */
40679                         duk_size_t q_blen, q_clen;
40680
40681                         p_start = DUK_HSTRING_GET_DATA(h_input);
40682                         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
40683                         p = p_start + prev_match_end_boff;
40684
40685                         h_sep = duk_known_hstring(thr, 0);  /* symbol already rejected above */
40686                         q_start = DUK_HSTRING_GET_DATA(h_sep);
40687                         q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
40688                         q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
40689
40690                         p_end -= q_blen;  /* ensure full memcmp() fits in while */
40691
40692                         match_start_coff = prev_match_end_coff;
40693
40694                         if (q_blen == 0) {
40695                                 /* Handle empty separator case: it will always match, and always
40696                                  * triggers the check in step 13.c.iii initially.  Note that we
40697                                  * must skip to either end of string or start of first codepoint,
40698                                  * skipping over any continuation bytes!
40699                                  *
40700                                  * Don't allow an empty string to match at the end of the input.
40701                                  */
40702
40703                                 matched = 1;  /* empty separator can always match */
40704
40705                                 match_start_coff++;
40706                                 p++;
40707                                 while (p < p_end) {
40708                                         if ((p[0] & 0xc0) != 0x80) {
40709                                                 goto found;
40710                                         }
40711                                         p++;
40712                                 }
40713                                 goto not_found;
40714                         }
40715
40716                         DUK_ASSERT(q_blen > 0 && q_clen > 0);
40717                         while (p <= p_end) {
40718                                 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
40719                                 DUK_ASSERT(q_blen > 0);  /* no issues with empty memcmp() */
40720                                 if (duk_memcmp((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
40721                                         /* never an empty match, so step 13.c.iii can't be triggered */
40722                                         goto found;
40723                                 }
40724
40725                                 /* track utf-8 non-continuation bytes */
40726                                 if ((p[0] & 0xc0) != 0x80) {
40727                                         match_start_coff++;
40728                                 }
40729                                 p++;
40730                         }
40731
40732                  not_found:
40733                         /* not found */
40734                         break;
40735
40736                  found:
40737                         matched = 1;
40738                         match_start_boff = (duk_uint32_t) (p - p_start);
40739                         match_end_coff = (duk_uint32_t) (match_start_coff + q_clen);  /* constrained by string length */
40740                         match_end_boff = (duk_uint32_t) (match_start_boff + q_blen);  /* ditto */
40741
40742                         /* empty match (may happen with empty separator) -> bump and continue */
40743                         if (prev_match_end_boff == match_end_boff) {
40744                                 prev_match_end_boff++;
40745                                 prev_match_end_coff++;
40746                                 continue;
40747                         }
40748                 }  /* if (is_regexp) */
40749
40750                 /* stack[0] = separator (string or regexp)
40751                  * stack[1] = limit
40752                  * stack[2] = input string
40753                  * stack[3] = result array
40754                  * stack[4] = regexp res_obj (if is_regexp)
40755                  */
40756
40757                 DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld",
40758                                      (long) match_start_boff, (long) match_start_coff,
40759                                      (long) match_end_boff, (long) match_end_coff,
40760                                      (long) prev_match_end_boff, (long) prev_match_end_coff));
40761
40762                 duk_push_lstring(thr,
40763                                  (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
40764                                  (duk_size_t) (match_start_boff - prev_match_end_boff));
40765                 duk_put_prop_index(thr, 3, arr_idx);
40766                 arr_idx++;
40767                 if (arr_idx >= limit) {
40768                         goto hit_limit;
40769                 }
40770
40771 #if defined(DUK_USE_REGEXP_SUPPORT)
40772                 if (is_regexp) {
40773                         duk_size_t i, len;
40774
40775                         len = duk_get_length(thr, 4);
40776                         for (i = 1; i < len; i++) {
40777                                 DUK_ASSERT(i <= DUK_UARRIDX_MAX);  /* cannot have >4G captures */
40778                                 duk_get_prop_index(thr, 4, (duk_uarridx_t) i);
40779                                 duk_put_prop_index(thr, 3, arr_idx);
40780                                 arr_idx++;
40781                                 if (arr_idx >= limit) {
40782                                         goto hit_limit;
40783                                 }
40784                         }
40785
40786                         duk_pop(thr);
40787                         /* lastIndex already set up for next match */
40788                 } else {
40789 #else  /* DUK_USE_REGEXP_SUPPORT */
40790                 {  /* unconditionally */
40791 #endif  /* DUK_USE_REGEXP_SUPPORT */
40792                         /* no action */
40793                 }
40794
40795                 prev_match_end_boff = match_end_boff;
40796                 prev_match_end_coff = match_end_coff;
40797                 continue;
40798         }  /* for */
40799
40800         /* Combined step 11 (empty string special case) and 14-15. */
40801
40802         DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld",
40803                              (long) prev_match_end_boff, (long) prev_match_end_coff));
40804
40805         if (DUK_HSTRING_GET_BYTELEN(h_input) > 0 || !matched) {
40806                 /* Add trailer if:
40807                  *   a) non-empty input
40808                  *   b) empty input and no (zero size) match found (step 11)
40809                  */
40810
40811                 duk_push_lstring(thr,
40812                                  (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
40813                                  (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
40814                 duk_put_prop_index(thr, 3, arr_idx);
40815                 /* No arr_idx update or limit check */
40816         }
40817
40818         return 1;
40819
40820  hit_limit:
40821 #if defined(DUK_USE_REGEXP_SUPPORT)
40822         if (is_regexp) {
40823                 duk_pop(thr);
40824         }
40825 #endif
40826
40827         return 1;
40828 }
40829
40830 /*
40831  *  Various
40832  */
40833
40834 #if defined(DUK_USE_REGEXP_SUPPORT)
40835 DUK_LOCAL void duk__to_regexp_helper(duk_hthread *thr, duk_idx_t idx, duk_bool_t force_new) {
40836         duk_hobject *h;
40837
40838         /* Shared helper for match() steps 3-4, search() steps 3-4. */
40839
40840         DUK_ASSERT(idx >= 0);
40841
40842         if (force_new) {
40843                 goto do_new;
40844         }
40845
40846         h = duk_get_hobject_with_class(thr, idx, DUK_HOBJECT_CLASS_REGEXP);
40847         if (!h) {
40848                 goto do_new;
40849         }
40850         return;
40851
40852  do_new:
40853         duk_push_hobject_bidx(thr, DUK_BIDX_REGEXP_CONSTRUCTOR);
40854         duk_dup(thr, idx);
40855         duk_new(thr, 1);  /* [ ... RegExp val ] -> [ ... res ] */
40856         duk_replace(thr, idx);
40857 }
40858 #endif  /* DUK_USE_REGEXP_SUPPORT */
40859
40860 #if defined(DUK_USE_REGEXP_SUPPORT)
40861 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_hthread *thr) {
40862         /* Easiest way to implement the search required by the specification
40863          * is to do a RegExp test() with lastIndex forced to zero.  To avoid
40864          * side effects on the argument, "clone" the RegExp if a RegExp was
40865          * given as input.
40866          *
40867          * The global flag of the RegExp should be ignored; setting lastIndex
40868          * to zero (which happens when "cloning" the RegExp) should have an
40869          * equivalent effect.
40870          */
40871
40872         DUK_ASSERT_TOP(thr, 1);
40873         (void) duk_push_this_coercible_to_string(thr);  /* at index 1 */
40874         duk__to_regexp_helper(thr, 0 /*index*/, 1 /*force_new*/);
40875
40876         /* stack[0] = regexp
40877          * stack[1] = string
40878          */
40879
40880         /* Avoid using RegExp.prototype methods, as they're writable and
40881          * configurable and may have been changed.
40882          */
40883
40884         duk_dup_0(thr);
40885         duk_dup_1(thr);  /* [ ... re_obj input ] */
40886         duk_regexp_match(thr);  /* -> [ ... res_obj ] */
40887
40888         if (!duk_is_object(thr, -1)) {
40889                 duk_push_int(thr, -1);
40890                 return 1;
40891         }
40892
40893         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INDEX);
40894         DUK_ASSERT(duk_is_number(thr, -1));
40895         return 1;
40896 }
40897 #endif  /* DUK_USE_REGEXP_SUPPORT */
40898
40899 #if defined(DUK_USE_REGEXP_SUPPORT)
40900 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_hthread *thr) {
40901         duk_bool_t global;
40902         duk_int_t prev_last_index;
40903         duk_int_t this_index;
40904         duk_int_t arr_idx;
40905
40906         DUK_ASSERT_TOP(thr, 1);
40907         (void) duk_push_this_coercible_to_string(thr);
40908         duk__to_regexp_helper(thr, 0 /*index*/, 0 /*force_new*/);
40909         global = duk_get_prop_stridx_boolean(thr, 0, DUK_STRIDX_GLOBAL, NULL);
40910         DUK_ASSERT_TOP(thr, 2);
40911
40912         /* stack[0] = regexp
40913          * stack[1] = string
40914          */
40915
40916         if (!global) {
40917                 duk_regexp_match(thr);  /* -> [ res_obj ] */
40918                 return 1;  /* return 'res_obj' */
40919         }
40920
40921         /* Global case is more complex. */
40922
40923         /* [ regexp string ] */
40924
40925         duk_push_int(thr, 0);
40926         duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
40927         duk_push_array(thr);
40928
40929         /* [ regexp string res_arr ] */
40930
40931         prev_last_index = 0;
40932         arr_idx = 0;
40933
40934         for (;;) {
40935                 DUK_ASSERT_TOP(thr, 3);
40936
40937                 duk_dup_0(thr);
40938                 duk_dup_1(thr);
40939                 duk_regexp_match(thr);  /* -> [ ... regexp string ] -> [ ... res_obj ] */
40940
40941                 if (!duk_is_object(thr, -1)) {
40942                         duk_pop(thr);
40943                         break;
40944                 }
40945
40946                 duk_get_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
40947                 DUK_ASSERT(duk_is_number(thr, -1));
40948                 this_index = duk_get_int(thr, -1);
40949                 duk_pop(thr);
40950
40951                 if (this_index == prev_last_index) {
40952                         this_index++;
40953                         duk_push_int(thr, this_index);
40954                         duk_put_prop_stridx_short(thr, 0, DUK_STRIDX_LAST_INDEX);
40955                 }
40956                 prev_last_index = this_index;
40957
40958                 duk_get_prop_index(thr, -1, 0);  /* match string */
40959                 duk_put_prop_index(thr, 2, (duk_uarridx_t) arr_idx);
40960                 arr_idx++;
40961                 duk_pop(thr);  /* res_obj */
40962         }
40963
40964         if (arr_idx == 0) {
40965                 duk_push_null(thr);
40966         }
40967
40968         return 1;  /* return 'res_arr' or 'null' */
40969 }
40970 #endif  /* DUK_USE_REGEXP_SUPPORT */
40971
40972 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_hthread *thr) {
40973         /* duk_concat() coerces arguments with ToString() in correct order */
40974         (void) duk_push_this_coercible_to_string(thr);
40975         duk_insert(thr, 0);  /* this is relatively expensive */
40976         duk_concat(thr, duk_get_top(thr));
40977         return 1;
40978 }
40979
40980 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_hthread *thr) {
40981         DUK_ASSERT_TOP(thr, 0);
40982         (void) duk_push_this_coercible_to_string(thr);
40983         duk_trim(thr, 0);
40984         DUK_ASSERT_TOP(thr, 1);
40985         return 1;
40986 }
40987
40988 #if defined(DUK_USE_ES6)
40989 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_hthread *thr) {
40990         duk_hstring *h_input;
40991         duk_size_t input_blen;
40992         duk_size_t result_len;
40993         duk_int_t count_signed;
40994         duk_uint_t count;
40995         const duk_uint8_t *src;
40996         duk_uint8_t *buf;
40997         duk_uint8_t *p;
40998         duk_double_t d;
40999 #if !defined(DUK_USE_PREFER_SIZE)
41000         duk_size_t copy_size;
41001         duk_uint8_t *p_end;
41002 #endif
41003
41004         DUK_ASSERT_TOP(thr, 1);
41005         h_input = duk_push_this_coercible_to_string(thr);
41006         DUK_ASSERT(h_input != NULL);
41007         input_blen = DUK_HSTRING_GET_BYTELEN(h_input);
41008
41009         /* Count is ToNumber() coerced; +Infinity must be always rejected
41010          * (even if input string is zero length), as well as negative values
41011          * and -Infinity.  -Infinity doesn't require an explicit check
41012          * because duk_get_int() clamps it to DUK_INT_MIN which gets rejected
41013          * as a negative value (regardless of input string length).
41014          */
41015         d = duk_to_number(thr, 0);
41016         if (duk_double_is_posinf(d)) {
41017                 goto fail_range;
41018         }
41019         count_signed = duk_get_int(thr, 0);
41020         if (count_signed < 0) {
41021                 goto fail_range;
41022         }
41023         count = (duk_uint_t) count_signed;
41024
41025         /* Overflow check for result length. */
41026         result_len = count * input_blen;
41027         if (count != 0 && result_len / count != input_blen) {
41028                 goto fail_range;
41029         }
41030
41031         /* Temporary fixed buffer, later converted to string. */
41032         buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(thr, result_len);
41033         DUK_ASSERT(buf != NULL);
41034         src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
41035         DUK_ASSERT(src != NULL);
41036
41037 #if defined(DUK_USE_PREFER_SIZE)
41038         p = buf;
41039         while (count-- > 0) {
41040                 duk_memcpy((void *) p, (const void *) src, input_blen);  /* copy size may be zero, but pointers are valid */
41041                 p += input_blen;
41042         }
41043 #else  /* DUK_USE_PREFER_SIZE */
41044         /* Take advantage of already copied pieces to speed up the process
41045          * especially for small repeated strings.
41046          */
41047         p = buf;
41048         p_end = p + result_len;
41049         copy_size = input_blen;
41050         for (;;) {
41051                 duk_size_t remain = (duk_size_t) (p_end - p);
41052                 DUK_DDD(DUK_DDDPRINT("remain=%ld, copy_size=%ld, input_blen=%ld, result_len=%ld",
41053                                      (long) remain, (long) copy_size, (long) input_blen,
41054                                      (long) result_len));
41055                 if (remain <= copy_size) {
41056                         /* If result_len is zero, this case is taken and does
41057                          * a zero size copy (with valid pointers).
41058                          */
41059                         duk_memcpy((void *) p, (const void *) src, remain);
41060                         break;
41061                 } else {
41062                         duk_memcpy((void *) p, (const void *) src, copy_size);
41063                         p += copy_size;
41064                 }
41065
41066                 src = (const duk_uint8_t *) buf;  /* Use buf as source for larger copies. */
41067                 copy_size = (duk_size_t) (p - buf);
41068         }
41069 #endif  /* DUK_USE_PREFER_SIZE */
41070
41071         /* XXX: It would be useful to be able to create a duk_hstring with
41072          * a certain byte size whose data area wasn't initialized and which
41073          * wasn't in the string table yet.  This would allow a string to be
41074          * constructed directly without a buffer temporary and when it was
41075          * finished, it could be injected into the string table.  Currently
41076          * this isn't possible because duk_hstrings are only tracked by the
41077          * intern table (they are not in heap_allocated).
41078          */
41079
41080         duk_buffer_to_string(thr, -1);  /* Safe if input is safe. */
41081         return 1;
41082
41083  fail_range:
41084         DUK_DCERROR_RANGE_INVALID_ARGS(thr);
41085 }
41086 #endif  /* DUK_USE_ES6 */
41087
41088 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_hthread *thr) {
41089         duk_hstring *h1;
41090         duk_hstring *h2;
41091         duk_size_t h1_len, h2_len, prefix_len;
41092         duk_small_int_t ret = 0;
41093         duk_small_int_t rc;
41094
41095         /* The current implementation of localeCompare() is simply a codepoint
41096          * by codepoint comparison, implemented with a simple string compare
41097          * because UTF-8 should preserve codepoint ordering (assuming valid
41098          * shortest UTF-8 encoding).
41099          *
41100          * The specification requires that the return value must be related
41101          * to the sort order: e.g. negative means that 'this' comes before
41102          * 'that' in sort order.  We assume an ascending sort order.
41103          */
41104
41105         /* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */
41106
41107         h1 = duk_push_this_coercible_to_string(thr);
41108         DUK_ASSERT(h1 != NULL);
41109
41110         h2 = duk_to_hstring(thr, 0);
41111         DUK_ASSERT(h2 != NULL);
41112
41113         h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
41114         h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
41115         prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
41116
41117         rc = (duk_small_int_t) duk_memcmp((const void *) DUK_HSTRING_GET_DATA(h1),
41118                                           (const void *) DUK_HSTRING_GET_DATA(h2),
41119                                           (size_t) prefix_len);
41120
41121         if (rc < 0) {
41122                 ret = -1;
41123                 goto done;
41124         } else if (rc > 0) {
41125                 ret = 1;
41126                 goto done;
41127         }
41128
41129         /* prefix matches, lengths matter now */
41130         if (h1_len > h2_len) {
41131                 ret = 1;
41132                 goto done;
41133         } else if (h1_len == h2_len) {
41134                 DUK_ASSERT(ret == 0);
41135                 goto done;
41136         }
41137         ret = -1;
41138         goto done;
41139
41140  done:
41141         duk_push_int(thr, (duk_int_t) ret);
41142         return 1;
41143 }
41144
41145 #if defined(DUK_USE_ES6)
41146 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_startswith_endswith(duk_hthread *thr) {
41147         duk_int_t magic;
41148         duk_hstring *h;
41149         duk_hstring *h_search;
41150         duk_size_t blen_search;
41151         const duk_uint8_t *p_cmp_start;
41152         duk_bool_t result;
41153
41154         h = duk_push_this_coercible_to_string(thr);
41155         DUK_ASSERT(h != NULL);
41156
41157         h_search = duk__str_tostring_notregexp(thr, 0);
41158         DUK_ASSERT(h_search != NULL);
41159
41160         magic = duk_get_current_magic(thr);
41161
41162         p_cmp_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
41163         blen_search = DUK_HSTRING_GET_BYTELEN(h_search);
41164
41165         if (duk_is_undefined(thr, 1)) {
41166                 if (magic) {
41167                         p_cmp_start = p_cmp_start + DUK_HSTRING_GET_BYTELEN(h) - blen_search;
41168                 } else {
41169                         /* p_cmp_start already OK */
41170                 }
41171         } else {
41172                 duk_int_t len;
41173                 duk_int_t pos;
41174
41175                 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= DUK_INT_MAX);
41176                 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
41177                 pos = duk_to_int_clamped(thr, 1, 0, len);
41178                 DUK_ASSERT(pos >= 0 && pos <= len);
41179
41180                 if (magic) {
41181                         p_cmp_start -= blen_search;  /* Conceptually subtracted last, but do already here. */
41182                 }
41183                 DUK_ASSERT(pos >= 0 && pos <= len);
41184
41185                 p_cmp_start += duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) pos);
41186         }
41187
41188         /* The main comparison can be done using a memcmp() rather than
41189          * doing codepoint comparisons: for CESU-8 strings there is a
41190          * canonical representation for every codepoint.  But we do need
41191          * to deal with the char/byte offset translation to find the
41192          * comparison range.
41193          */
41194
41195         result = 0;
41196         if (p_cmp_start >= DUK_HSTRING_GET_DATA(h) &&
41197             (duk_size_t) (p_cmp_start - (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h)) + blen_search <= DUK_HSTRING_GET_BYTELEN(h)) {
41198                 if (duk_memcmp((const void *) p_cmp_start,
41199                                (const void *) DUK_HSTRING_GET_DATA(h_search),
41200                                (size_t) blen_search) == 0) {
41201                         result = 1;
41202                 }
41203         }
41204
41205         duk_push_boolean(thr, result);
41206         return 1;
41207 }
41208 #endif  /* DUK_USE_ES6 */
41209
41210 #if defined(DUK_USE_ES6)
41211 DUK_INTERNAL duk_ret_t duk_bi_string_prototype_includes(duk_hthread *thr) {
41212         duk_hstring *h;
41213         duk_hstring *h_search;
41214         duk_int_t len;
41215         duk_int_t pos;
41216
41217         h = duk_push_this_coercible_to_string(thr);
41218         DUK_ASSERT(h != NULL);
41219
41220         h_search = duk__str_tostring_notregexp(thr, 0);
41221         DUK_ASSERT(h_search != NULL);
41222
41223         len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
41224         pos = duk_to_int_clamped(thr, 1, 0, len);
41225         DUK_ASSERT(pos >= 0 && pos <= len);
41226
41227         pos = duk__str_search_shared(thr, h, h_search, pos, 0 /*backwards*/);
41228         duk_push_boolean(thr, pos >= 0);
41229         return 1;
41230 }
41231 #endif  /* DUK_USE_ES6 */
41232 #endif  /* DUK_USE_STRING_BUILTIN */
41233 #line 1 "duk_bi_symbol.c"
41234 /*
41235  *  Symbol built-in
41236  */
41237
41238 /* #include duk_internal.h -> already included */
41239
41240 #if defined(DUK_USE_SYMBOL_BUILTIN)
41241
41242 /*
41243  *  Constructor
41244  */
41245
41246 DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_hthread *thr) {
41247         const duk_uint8_t *desc;
41248         duk_size_t len;
41249         duk_uint8_t *buf;
41250         duk_uint8_t *p;
41251         duk_int_t magic;
41252
41253         magic = duk_get_current_magic(thr);
41254         if (duk_is_undefined(thr, 0) && (magic == 0)) {
41255                 /* Symbol() accepts undefined and empty string, but they are
41256                  * treated differently.
41257                  */
41258                 desc = NULL;
41259                 len = 0;
41260         } else {
41261                 /* Symbol.for() coerces undefined to 'undefined' */
41262                 desc = (const duk_uint8_t *) duk_to_lstring(thr, 0, &len);
41263         }
41264
41265         /* Maximum symbol data length:
41266          *   +1    initial byte (0x80 or 0x81)
41267          *   +len  description
41268          *   +1    0xff after description, before unique suffix
41269          *   +17   autogenerated unique suffix: 'ffffffff-ffffffff' is longest
41270          *   +1    0xff after unique suffix for symbols with undefined description
41271          */
41272         buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, 1 + len + 1 + 17 + 1);
41273         DUK_ASSERT(buf != NULL);
41274         p = buf + 1;
41275         DUK_ASSERT(desc != NULL || len == 0);  /* may be NULL if len is 0 */
41276         duk_memcpy_unsafe((void *) p, (const void *) desc, len);
41277         p += len;
41278         if (magic == 0) {
41279                 /* Symbol(): create unique symbol.  Use two 32-bit values
41280                  * to avoid dependency on 64-bit types and 64-bit integer
41281                  * formatting (at least for now).
41282                  */
41283                 if (++thr->heap->sym_counter[0] == 0) {
41284                         thr->heap->sym_counter[1]++;
41285                 }
41286                 p += DUK_SPRINTF((char *) p, "\xFF" "%lx-%lx",
41287                                  (unsigned long) thr->heap->sym_counter[1],
41288                                  (unsigned long) thr->heap->sym_counter[0]);
41289                 if (desc == NULL) {
41290                         /* Special case for 'undefined' description, trailing
41291                          * 0xff distinguishes from empty string description,
41292                          * but needs minimal special case handling elsewhere.
41293                          */
41294                         *p++ = 0xff;
41295                 }
41296                 buf[0] = 0x81;
41297         } else {
41298                 /* Symbol.for(): create a global symbol */
41299                 buf[0] = 0x80;
41300         }
41301
41302         duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
41303         DUK_DDD(DUK_DDDPRINT("created symbol: %!T", duk_get_tval(thr, -1)));
41304         return 1;
41305 }
41306
41307 DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_hthread *thr, duk_tval *tv_arg) {
41308         duk_tval *tv;
41309         duk_tval tv_val;
41310         duk_hobject *h_obj;
41311         duk_hstring *h_str;
41312
41313         DUK_ASSERT(tv_arg != NULL);
41314
41315         /* XXX: add internal helper: duk_auto_unbox_tval(thr, tv, mask); */
41316         /* XXX: add internal helper: duk_auto_unbox(thr, tv, idx); */
41317
41318         tv = tv_arg;
41319         if (DUK_TVAL_IS_OBJECT(tv)) {
41320                 h_obj = DUK_TVAL_GET_OBJECT(tv);
41321                 DUK_ASSERT(h_obj != NULL);
41322                 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_SYMBOL) {
41323                         if (!duk_hobject_get_internal_value(thr->heap, h_obj, &tv_val)) {
41324                                 return NULL;
41325                         }
41326                         tv = &tv_val;
41327                 } else {
41328                         return NULL;
41329                 }
41330         }
41331
41332         if (!DUK_TVAL_IS_STRING(tv)) {
41333                 return NULL;
41334         }
41335         h_str = DUK_TVAL_GET_STRING(tv);
41336         DUK_ASSERT(h_str != NULL);
41337
41338         /* Here symbol is more expected than not. */
41339         if (DUK_UNLIKELY(!DUK_HSTRING_HAS_SYMBOL(h_str))) {
41340                 return NULL;
41341         }
41342
41343         return h_str;
41344 }
41345
41346 DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_hthread *thr) {
41347         duk_hstring *h_str;
41348
41349         h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
41350         if (h_str == NULL) {
41351                 return DUK_RET_TYPE_ERROR;
41352         }
41353
41354         if (duk_get_current_magic(thr) == 0) {
41355                 /* .toString() */
41356                 duk_push_symbol_descriptive_string(thr, h_str);
41357         } else {
41358                 /* .valueOf() */
41359                 duk_push_hstring(thr, h_str);
41360         }
41361         return 1;
41362 }
41363
41364 DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_hthread *thr) {
41365         duk_hstring *h;
41366         const duk_uint8_t *p;
41367
41368         /* Argument must be a symbol but not checked here.  The initial byte
41369          * check will catch non-symbol strings.
41370          */
41371         h = duk_require_hstring(thr, 0);
41372         DUK_ASSERT(h != NULL);
41373
41374         p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
41375         DUK_ASSERT(p != NULL);
41376
41377         /* Even for zero length strings there's at least one NUL byte so
41378          * we can safely check the initial byte.
41379          */
41380         if (p[0] == 0x80) {
41381                 /* Global symbol, return its key (bytes just after the initial byte). */
41382                 duk_push_lstring(thr, (const char *) (p + 1), (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h) - 1));
41383                 return 1;
41384         } else if (p[0] == 0x81 || p[0] == 0x82 || p[0] == 0xff) {
41385                 /* Local symbol or hidden symbol, return undefined. */
41386                 return 0;
41387         }
41388
41389         /* Covers normal strings and unknown initial bytes. */
41390         return DUK_RET_TYPE_ERROR;
41391 }
41392
41393 DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_hthread *thr) {
41394         duk_hstring *h_str;
41395
41396         h_str = duk__auto_unbox_symbol(thr, DUK_HTHREAD_THIS_PTR(thr));
41397         if (h_str == NULL) {
41398                 return DUK_RET_TYPE_ERROR;
41399         }
41400         duk_push_hstring(thr, h_str);
41401         return 1;
41402 }
41403
41404 #endif  /* DUK_USE_SYMBOL_BUILTIN */
41405 #line 1 "duk_bi_thread.c"
41406 /*
41407  *  Thread builtins
41408  */
41409
41410 /* #include duk_internal.h -> already included */
41411
41412 /*
41413  *  Constructor
41414  */
41415
41416 #if defined(DUK_USE_COROUTINE_SUPPORT)
41417 DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_hthread *thr) {
41418         duk_hthread *new_thr;
41419         duk_hobject *func;
41420
41421         /* Check that the argument is callable; this is not 100% because we
41422          * don't allow native functions to be a thread's initial function.
41423          * Resume will reject such functions in any case.
41424          */
41425         /* XXX: need a duk_require_func_promote_lfunc() */
41426         func = duk_require_hobject_promote_lfunc(thr, 0);
41427         DUK_ASSERT(func != NULL);
41428         duk_require_callable(thr, 0);
41429
41430         duk_push_thread(thr);
41431         new_thr = (duk_hthread *) duk_known_hobject(thr, -1);
41432         new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
41433
41434         /* push initial function call to new thread stack; this is
41435          * picked up by resume().
41436          */
41437         duk_push_hobject(new_thr, func);
41438
41439         return 1;  /* return thread */
41440 }
41441 #endif
41442
41443 /*
41444  *  Resume a thread.
41445  *
41446  *  The thread must be in resumable state, either (a) new thread which hasn't
41447  *  yet started, or (b) a thread which has previously yielded.  This method
41448  *  must be called from an ECMAScript function.
41449  *
41450  *  Args:
41451  *    - thread
41452  *    - value
41453  *    - isError (defaults to false)
41454  *
41455  *  Note: yield and resume handling is currently asymmetric.
41456  */
41457
41458 #if defined(DUK_USE_COROUTINE_SUPPORT)
41459 DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_hthread *ctx) {
41460         duk_hthread *thr = (duk_hthread *) ctx;
41461         duk_hthread *thr_resume;
41462         duk_hobject *caller_func;
41463         duk_small_uint_t is_error;
41464
41465         DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
41466                              (duk_tval *) duk_get_tval(thr, 0),
41467                              (duk_tval *) duk_get_tval(thr, 1),
41468                              (duk_tval *) duk_get_tval(thr, 2)));
41469
41470         DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
41471         DUK_ASSERT(thr->heap->curr_thread == thr);
41472
41473         thr_resume = duk_require_hthread(thr, 0);
41474         DUK_ASSERT(duk_get_top(thr) == 3);
41475         is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr);
41476         DUK_ASSERT(duk_get_top(thr) == 2);
41477
41478         /* [ thread value ] */
41479
41480         /*
41481          *  Thread state and calling context checks
41482          */
41483
41484         if (thr->callstack_top < 2) {
41485                 DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
41486                 goto state_error;
41487         }
41488         DUK_ASSERT(thr->callstack_curr != NULL);
41489         DUK_ASSERT(thr->callstack_curr->parent != NULL);
41490         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);  /* us */
41491         DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
41492         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL);  /* caller */
41493
41494         caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
41495         if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
41496                 DUK_DD(DUK_DDPRINT("resume state invalid: caller must be ECMAScript code"));
41497                 goto state_error;
41498         }
41499
41500         /* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
41501          * like for yield.
41502          */
41503
41504         if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
41505             thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
41506                 DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"));
41507                 goto state_error;
41508         }
41509
41510         DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
41511                    thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
41512
41513         /* Further state-dependent pre-checks */
41514
41515         if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
41516                 /* no pre-checks now, assume a previous yield() has left things in
41517                  * tip-top shape (longjmp handler will assert for these).
41518                  */
41519         } else {
41520                 duk_hobject *h_fun;
41521
41522                 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
41523
41524                 /* The initial function must be an ECMAScript function (but
41525                  * can be bound).  We must make sure of that before we longjmp
41526                  * because an error in the RESUME handler call processing will
41527                  * not be handled very cleanly.
41528                  */
41529                 if ((thr_resume->callstack_top != 0) ||
41530                     (thr_resume->valstack_top - thr_resume->valstack != 1)) {
41531                         goto state_error;
41532                 }
41533
41534                 duk_push_tval(thr, DUK_GET_TVAL_NEGIDX(thr_resume, -1));
41535                 duk_resolve_nonbound_function(thr);
41536                 h_fun = duk_require_hobject(thr, -1);  /* reject lightfuncs on purpose */
41537                 if (!DUK_HOBJECT_IS_CALLABLE(h_fun) || !DUK_HOBJECT_IS_COMPFUNC(h_fun)) {
41538                         goto state_error;
41539                 }
41540                 duk_pop(thr);
41541         }
41542
41543         /*
41544          *  The error object has been augmented with a traceback and other
41545          *  info from its creation point -- usually another thread.  The
41546          *  error handler is called here right before throwing, but it also
41547          *  runs in the resumer's thread.  It might be nice to get a traceback
41548          *  from the resumee but this is not the case now.
41549          */
41550
41551 #if defined(DUK_USE_AUGMENT_ERROR_THROW)
41552         if (is_error) {
41553                 DUK_ASSERT_TOP(thr, 2);  /* value (error) is at stack top */
41554                 duk_err_augment_error_throw(thr);  /* in resumer's context */
41555         }
41556 #endif
41557
41558 #if defined(DUK_USE_DEBUG)
41559         if (is_error) {
41560                 DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
41561                                      (duk_tval *) duk_get_tval(thr, 0),
41562                                      (duk_tval *) duk_get_tval(thr, 1)));
41563         } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
41564                 DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
41565                                      (duk_tval *) duk_get_tval(thr, 0),
41566                                      (duk_tval *) duk_get_tval(thr, 1)));
41567         } else {
41568                 DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
41569                                      (duk_tval *) duk_get_tval(thr, 0),
41570                                      (duk_tval *) duk_get_tval(thr, 1)));
41571         }
41572 #endif
41573
41574         thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
41575
41576         /* lj value2: thread */
41577         DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
41578         DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]);  /* side effects */
41579
41580         /* lj value1: value */
41581         DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
41582         DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]);  /* side effects */
41583         DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
41584
41585         thr->heap->lj.iserror = is_error;
41586
41587         DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* call is from executor, so we know we have a jmpbuf */
41588         duk_err_longjmp(thr);  /* execution resumes in bytecode executor */
41589         DUK_UNREACHABLE();
41590         /* Never here, fall through to error (from compiler point of view). */
41591
41592  state_error:
41593         DUK_DCERROR_TYPE_INVALID_STATE(thr);
41594 }
41595 #endif
41596
41597 /*
41598  *  Yield the current thread.
41599  *
41600  *  The thread must be in yieldable state: it must have a resumer, and there
41601  *  must not be any yield-preventing calls (native calls and constructor calls,
41602  *  currently) in the thread's call stack (otherwise a resume would not be
41603  *  possible later).  This method must be called from an ECMAScript function.
41604  *
41605  *  Args:
41606  *    - value
41607  *    - isError (defaults to false)
41608  *
41609  *  Note: yield and resume handling is currently asymmetric.
41610  */
41611
41612 #if defined(DUK_USE_COROUTINE_SUPPORT)
41613 DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_hthread *thr) {
41614         duk_hobject *caller_func;
41615         duk_small_uint_t is_error;
41616
41617         DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
41618                              (duk_tval *) duk_get_tval(thr, 0),
41619                              (duk_tval *) duk_get_tval(thr, 1)));
41620
41621         DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
41622         DUK_ASSERT(thr->heap->curr_thread == thr);
41623
41624         DUK_ASSERT(duk_get_top(thr) == 2);
41625         is_error = (duk_small_uint_t) duk_to_boolean_top_pop(thr);
41626         DUK_ASSERT(duk_get_top(thr) == 1);
41627
41628         /* [ value ] */
41629
41630         /*
41631          *  Thread state and calling context checks
41632          */
41633
41634         if (!thr->resumer) {
41635                 DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer"));
41636                 goto state_error;
41637         }
41638         DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
41639
41640         if (thr->callstack_top < 2) {
41641                 DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
41642                 goto state_error;
41643         }
41644         DUK_ASSERT(thr->callstack_curr != NULL);
41645         DUK_ASSERT(thr->callstack_curr->parent != NULL);
41646         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);  /* us */
41647         DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
41648         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL);  /* caller */
41649
41650         caller_func = DUK_ACT_GET_FUNC(thr->callstack_curr->parent);
41651         if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
41652                 DUK_DD(DUK_DDPRINT("yield state invalid: caller must be ECMAScript code"));
41653                 goto state_error;
41654         }
41655
41656         DUK_ASSERT(thr->callstack_preventcount >= 1);  /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
41657         if (thr->callstack_preventcount != 1) {
41658                 /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
41659                 DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)",
41660                                    (long) thr->callstack_preventcount));
41661                 goto state_error;
41662         }
41663
41664         /*
41665          *  The error object has been augmented with a traceback and other
41666          *  info from its creation point -- usually the current thread.
41667          *  The error handler, however, is called right before throwing
41668          *  and runs in the yielder's thread.
41669          */
41670
41671 #if defined(DUK_USE_AUGMENT_ERROR_THROW)
41672         if (is_error) {
41673                 DUK_ASSERT_TOP(thr, 1);  /* value (error) is at stack top */
41674                 duk_err_augment_error_throw(thr);  /* in yielder's context */
41675         }
41676 #endif
41677
41678 #if defined(DUK_USE_DEBUG)
41679         if (is_error) {
41680                 DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
41681                                      (duk_tval *) duk_get_tval(thr, 0)));
41682         } else {
41683                 DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
41684                                      (duk_tval *) duk_get_tval(thr, 0)));
41685         }
41686 #endif
41687
41688         /*
41689          *  Process yield
41690          *
41691          *  After longjmp(), processing continues in bytecode executor longjmp
41692          *  handler, which will e.g. update thr->resumer to NULL.
41693          */
41694
41695         thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
41696
41697         /* lj value1: value */
41698         DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
41699         DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]);  /* side effects */
41700         DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
41701
41702         thr->heap->lj.iserror = is_error;
41703
41704         DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* call is from executor, so we know we have a jmpbuf */
41705         duk_err_longjmp(thr);  /* execution resumes in bytecode executor */
41706         DUK_UNREACHABLE();
41707         /* Never here, fall through to error (from compiler point of view). */
41708
41709  state_error:
41710         DUK_DCERROR_TYPE_INVALID_STATE(thr);
41711 }
41712 #endif
41713
41714 #if defined(DUK_USE_COROUTINE_SUPPORT)
41715 DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_hthread *thr) {
41716         duk_push_current_thread(thr);
41717         return 1;
41718 }
41719 #endif
41720 #line 1 "duk_bi_thrower.c"
41721 /*
41722  *  Type error thrower, E5 Section 13.2.3.
41723  */
41724
41725 /* #include duk_internal.h -> already included */
41726
41727 DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_hthread *thr) {
41728         DUK_DCERROR_TYPE_INVALID_ARGS(thr);
41729 }
41730 #line 1 "duk_debug_fixedbuffer.c"
41731 /*
41732  *  Fixed buffer helper useful for debugging, requires no allocation
41733  *  which is critical for debugging.
41734  */
41735
41736 /* #include duk_internal.h -> already included */
41737
41738 #if defined(DUK_USE_DEBUG)
41739
41740 DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
41741         duk_size_t avail;
41742         duk_size_t copylen;
41743
41744         avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
41745         if (length > avail) {
41746                 copylen = avail;
41747                 fb->truncated = 1;
41748         } else {
41749                 copylen = length;
41750         }
41751         duk_memcpy_unsafe(fb->buffer + fb->offset, buffer, copylen);
41752         fb->offset += copylen;
41753 }
41754
41755 DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
41756         duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1);
41757 }
41758
41759 DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
41760         duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
41761 }
41762
41763 DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
41764         duk_size_t avail;
41765         va_list ap;
41766
41767         va_start(ap, fmt);
41768         avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
41769         if (avail > 0) {
41770                 duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap);
41771                 if (res < 0) {
41772                         /* error */
41773                 } else if ((duk_size_t) res >= avail) {
41774                         /* (maybe) truncated */
41775                         fb->offset += avail;
41776                         if ((duk_size_t) res > avail) {
41777                                 /* actual chars dropped (not just NUL term) */
41778                                 fb->truncated = 1;
41779                         }
41780                 } else {
41781                         /* normal */
41782                         fb->offset += (duk_size_t) res;
41783                 }
41784         }
41785         va_end(ap);
41786 }
41787
41788 DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) {
41789         char buf[64+1];
41790         duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size);
41791         buf[sizeof(buf) - 1] = (char) 0;
41792         duk_fb_put_cstring(fb, buf);
41793 }
41794
41795 DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
41796         return (fb->offset >= fb->length);
41797 }
41798
41799 #endif  /* DUK_USE_DEBUG */
41800 #line 1 "duk_debug_vsnprintf.c"
41801 /*
41802  *  Custom formatter for debug printing, allowing Duktape specific data
41803  *  structures (such as tagged values and heap objects) to be printed with
41804  *  a nice format string.  Because debug printing should not affect execution
41805  *  state, formatting here must be independent of execution (see implications
41806  *  below) and must not allocate memory.
41807  *
41808  *  Custom format tags begin with a '%!' to safely distinguish them from
41809  *  standard format tags.  The following conversions are supported:
41810  *
41811  *     %!T    tagged value (duk_tval *)
41812  *     %!O    heap object (duk_heaphdr *)
41813  *     %!I    decoded bytecode instruction
41814  *     %!C    bytecode instruction opcode name (arg is long)
41815  *
41816  *  Everything is serialized in a JSON-like manner.  The default depth is one
41817  *  level, internal prototype is not followed, and internal properties are not
41818  *  serialized.  The following modifiers change this behavior:
41819  *
41820  *     @      print pointers
41821  *     #      print binary representations (where applicable)
41822  *     d      deep traversal of own properties (not prototype)
41823  *     p      follow prototype chain (useless without 'd')
41824  *     i      include internal properties (other than prototype)
41825  *     x      hexdump buffers
41826  *     h      heavy formatting
41827  *
41828  *  For instance, the following serializes objects recursively, but does not
41829  *  follow the prototype chain nor print internal properties: "%!dO".
41830  *
41831  *  Notes:
41832  *
41833  *    * Standard snprintf return value semantics seem to vary.  This
41834  *      implementation returns the number of bytes it actually wrote
41835  *      (excluding the null terminator).  If retval == buffer size,
41836  *      output was truncated (except for corner cases).
41837  *
41838  *    * Output format is intentionally different from ECMAScript
41839  *      formatting requirements, as formatting here serves debugging
41840  *      of internals.
41841  *
41842  *    * Depth checking (and updating) is done in each type printer
41843  *      separately, to allow them to call each other freely.
41844  *
41845  *    * Some pathological structures might take ages to print (e.g.
41846  *      self recursion with 100 properties pointing to the object
41847  *      itself).  To guard against these, each printer also checks
41848  *      whether the output buffer is full; if so, early exit.
41849  *
41850  *    * Reference loops are detected using a loop stack.
41851  */
41852
41853 /* #include duk_internal.h -> already included */
41854
41855 #if defined(DUK_USE_DEBUG)
41856
41857 /* #include stdio.h -> already included */
41858 /* #include stdarg.h -> already included */
41859 #include <string.h>
41860
41861 /* list of conversion specifiers that terminate a format tag;
41862  * this is unfortunately guesswork.
41863  */
41864 #define DUK__ALLOWED_STANDARD_SPECIFIERS  "diouxXeEfFgGaAcsCSpnm"
41865
41866 /* maximum length of standard format tag that we support */
41867 #define DUK__MAX_FORMAT_TAG_LENGTH  32
41868
41869 /* heapobj recursion depth when deep printing is selected */
41870 #define DUK__DEEP_DEPTH_LIMIT  8
41871
41872 /* maximum recursion depth for loop detection stacks */
41873 #define DUK__LOOP_STACK_DEPTH  256
41874
41875 /* must match bytecode defines now; build autogenerate? */
41876 DUK_LOCAL const char * const duk__bc_optab[256] = {
41877         "LDREG", "STREG", "JUMP", "LDCONST", "LDINT", "LDINTX", "LDTHIS", "LDUNDEF",
41878         "LDNULL", "LDTRUE", "LDFALSE", "GETVAR", "BNOT", "LNOT", "UNM", "UNP",
41879         "EQ_RR", "EQ_CR", "EQ_RC", "EQ_CC", "NEQ_RR", "NEQ_CR", "NEQ_RC", "NEQ_CC",
41880         "SEQ_RR", "SEQ_CR", "SEQ_RC", "SEQ_CC", "SNEQ_RR", "SNEQ_CR", "SNEQ_RC", "SNEQ_CC",
41881
41882         "GT_RR", "GT_CR", "GT_RC", "GT_CC", "GE_RR", "GE_CR", "GE_RC", "GE_CC",
41883         "LT_RR", "LT_CR", "LT_RC", "LT_CC", "LE_RR", "LE_CR", "LE_RC", "LE_CC",
41884         "IFTRUE_R", "IFTRUE_C", "IFFALSE_R", "IFFALSE_C", "ADD_RR", "ADD_CR", "ADD_RC", "ADD_CC",
41885         "SUB_RR", "SUB_CR", "SUB_RC", "SUB_CC", "MUL_RR", "MUL_CR", "MUL_RC", "MUL_CC",
41886
41887         "DIV_RR", "DIV_CR", "DIV_RC", "DIV_CC", "MOD_RR", "MOD_CR", "MOD_RC", "MOD_CC",
41888         "EXP_RR", "EXP_CR", "EXP_RC", "EXP_CC", "BAND_RR", "BAND_CR", "BAND_RC", "BAND_CC",
41889         "BOR_RR", "BOR_CR", "BOR_RC", "BOR_CC", "BXOR_RR", "BXOR_CR", "BXOR_RC", "BXOR_CC",
41890         "BASL_RR", "BASL_CR", "BASL_RC", "BASL_CC", "BLSR_RR", "BLSR_CR", "BLSR_RC", "BLSR_CC",
41891
41892         "BASR_RR", "BASR_CR", "BASR_RC", "BASR_CC", "INSTOF_RR", "INSTOF_CR", "INSTOF_RC", "INSTOF_CC",
41893         "IN_RR", "IN_CR", "IN_RC", "IN_CC", "GETPROP_RR", "GETPROP_CR", "GETPROP_RC", "GETPROP_CC",
41894         "PUTPROP_RR", "PUTPROP_CR", "PUTPROP_RC", "PUTPROP_CC", "DELPROP_RR", "DELPROP_CR", "DELPROP_RC", "DELPROP_CC",
41895         "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
41896
41897         "PREINCP_RR", "PREINCP_CR", "PREINCP_RC", "PREINCP_CC", "PREDECP_RR", "PREDECP_CR", "PREDECP_RC", "PREDECP_CC",
41898         "POSTINCP_RR", "POSTINCP_CR", "POSTINCP_RC", "POSTINCP_CC", "POSTDECP_RR", "POSTDECP_CR", "POSTDECP_RC", "POSTDECP_CC",
41899         "DECLVAR_RR", "DECLVAR_CR", "DECLVAR_RC", "DECLVAR_CC", "REGEXP_RR", "REGEXP_RC", "REGEXP_CR", "REGEXP_CC",
41900         "CLOSURE", "TYPEOF", "TYPEOFID", "PUTVAR", "DELVAR", "RETREG", "RETUNDEF", "RETCONST",
41901
41902         "RETCONSTN", "LABEL", "ENDLABEL", "BREAK", "CONTINUE", "TRYCATCH", "ENDTRY", "ENDCATCH",
41903         "ENDFIN", "THROW", "INVLHS", "CSREG", "CSVAR_RR", "CSVAR_CR", "CSVAR_RC", "CSVAR_CC",
41904         "CALL0", "CALL1", "CALL2", "CALL3", "CALL4", "CALL5", "CALL6", "CALL7",
41905         "CALL8", "CALL9", "CALL10", "CALL11", "CALL12", "CALL13", "CALL14", "CALL15",
41906
41907         "NEWOBJ", "NEWARR", "MPUTOBJ", "MPUTOBJI", "INITSET", "INITGET", "MPUTARR", "MPUTARRI",
41908         "SETALEN", "INITENUM", "NEXTENUM", "NEWTARGET", "DEBUGGER", "NOP", "INVALID", "UNUSED207",
41909         "GETPROPC_RR", "GETPROPC_CR", "GETPROPC_RC", "GETPROPC_CC", "UNUSED212", "UNUSED213", "UNUSED214", "UNUSED215",
41910         "UNUSED216", "UNUSED217", "UNUSED218", "UNUSED219", "UNUSED220", "UNUSED221", "UNUSED222", "UNUSED223",
41911
41912         "UNUSED224", "UNUSED225", "UNUSED226", "UNUSED227", "UNUSED228", "UNUSED229", "UNUSED230", "UNUSED231",
41913         "UNUSED232", "UNUSED233", "UNUSED234", "UNUSED235", "UNUSED236", "UNUSED237", "UNUSED238", "UNUSED239",
41914         "UNUSED240", "UNUSED241", "UNUSED242", "UNUSED243", "UNUSED244", "UNUSED245", "UNUSED246", "UNUSED247",
41915         "UNUSED248", "UNUSED249", "UNUSED250", "UNUSED251", "UNUSED252", "UNUSED253", "UNUSED254", "UNUSED255"
41916 };
41917
41918 typedef struct duk__dprint_state duk__dprint_state;
41919 struct duk__dprint_state {
41920         duk_fixedbuffer *fb;
41921
41922         /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice
41923          * to not couple these two mechanisms unnecessarily.
41924          */
41925         duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH];
41926         duk_int_t loop_stack_index;
41927         duk_int_t loop_stack_limit;
41928
41929         duk_int_t depth;
41930         duk_int_t depth_limit;
41931
41932         duk_bool_t pointer;
41933         duk_bool_t heavy;
41934         duk_bool_t binary;
41935         duk_bool_t follow_proto;
41936         duk_bool_t internal;
41937         duk_bool_t hexdump;
41938 };
41939
41940 /* helpers */
41941 DUK_LOCAL_DECL void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, duk_bool_t quotes);
41942 DUK_LOCAL_DECL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h);
41943 DUK_LOCAL_DECL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h);
41944 DUK_LOCAL_DECL void duk__print_tval(duk__dprint_state *st, duk_tval *tv);
41945 DUK_LOCAL_DECL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins);
41946 DUK_LOCAL_DECL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
41947 DUK_LOCAL_DECL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
41948 DUK_LOCAL_DECL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h);
41949
41950 DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
41951         duk_fixedbuffer *fb = st->fb;
41952
41953         if (st->heavy) {
41954                 duk_fb_sprintf(fb, "(%p)", (void *) h);
41955         }
41956
41957         if (!h) {
41958                 return;
41959         }
41960
41961         if (st->binary) {
41962                 duk_size_t i;
41963                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
41964                 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
41965                         duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
41966                 }
41967                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
41968         }
41969
41970 #if defined(DUK_USE_REFERENCE_COUNTING)  /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
41971         if (st->heavy) {
41972                 duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld,"
41973                                "reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
41974                                (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
41975                                (void *) DUK_HEAPHDR_GET_PREV(NULL, h),
41976                                (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(h),
41977                                (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
41978                                (long) DUK_HEAPHDR_GET_TYPE(h),
41979                                (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
41980                                (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
41981                                (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
41982                                (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
41983         }
41984 #else
41985         if (st->heavy) {
41986                 duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
41987                                (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
41988                                (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
41989                                (long) DUK_HEAPHDR_GET_TYPE(h),
41990                                (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
41991                                (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
41992                                (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
41993                                (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
41994         }
41995 #endif
41996 }
41997
41998 DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) {
41999         duk_fixedbuffer *fb = st->fb;
42000
42001         if (st->heavy) {
42002                 duk_fb_sprintf(fb, "(%p)", (void *) h);
42003         }
42004
42005         if (!h) {
42006                 return;
42007         }
42008
42009         if (st->binary) {
42010                 duk_size_t i;
42011                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
42012                 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
42013                         duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
42014                 }
42015                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
42016         }
42017
42018 #if defined(DUK_USE_REFERENCE_COUNTING)
42019         if (st->heavy) {
42020                 duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
42021                                (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h),
42022                                (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
42023                                (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
42024                                (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
42025                                (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
42026                                (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
42027                                (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
42028         }
42029 #else
42030         if (st->heavy) {
42031                 duk_fb_sprintf(fb, "[h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
42032                                (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
42033                                (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
42034                                (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
42035                                (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
42036                                (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
42037                                (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
42038         }
42039 #endif
42040 }
42041
42042 DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_bool_t quotes) {
42043         duk_fixedbuffer *fb = st->fb;
42044         const duk_uint8_t *p;
42045         const duk_uint8_t *p_end;
42046
42047         /* terminal type: no depth check */
42048
42049         if (duk_fb_is_full(fb)) {
42050                 return;
42051         }
42052
42053         duk__print_shared_heaphdr_string(st, &h->hdr);
42054
42055         if (!h) {
42056                 duk_fb_put_cstring(fb, "NULL");
42057                 return;
42058         }
42059
42060         p = DUK_HSTRING_GET_DATA(h);
42061         p_end = p + DUK_HSTRING_GET_BYTELEN(h);
42062
42063         if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) {
42064                 /* If property key begins with underscore, encode it with
42065                  * forced quotes (e.g. "_Foo") to distinguish it from encoded
42066                  * internal properties (e.g. \x82Bar -> _Bar).
42067                  */
42068                 quotes = 1;
42069         }
42070
42071         if (quotes) {
42072                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
42073         }
42074         while (p < p_end) {
42075                 duk_uint8_t ch = *p++;
42076
42077                 /* two special escapes: '\' and '"', other printables as is */
42078                 if (ch == '\\') {
42079                         duk_fb_sprintf(fb, "\\\\");
42080                 } else if (ch == '"') {
42081                         duk_fb_sprintf(fb, "\\\"");
42082                 } else if (ch >= 0x20 && ch <= 0x7e) {
42083                         duk_fb_put_byte(fb, ch);
42084                 } else if (ch == 0x82 && !quotes) {
42085                         /* encode \x82Bar as _Bar if no quotes are
42086                          * applied, this is for readable internal keys.
42087                          */
42088                         duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE);
42089                 } else {
42090                         duk_fb_sprintf(fb, "\\x%02lx", (unsigned long) ch);
42091                 }
42092         }
42093         if (quotes) {
42094                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
42095         }
42096 #if defined(DUK_USE_REFERENCE_COUNTING)
42097         /* XXX: limit to quoted strings only, to save keys from being cluttered? */
42098         duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
42099 #endif
42100 }
42101
42102 #define DUK__COMMA()  do { \
42103                 if (first) { \
42104                         first = 0; \
42105                 } else { \
42106                         duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); \
42107                 } \
42108         } while (0)
42109
42110 DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
42111         duk_fixedbuffer *fb = st->fb;
42112         duk_uint_fast32_t i;
42113         duk_tval *tv;
42114         duk_hstring *key;
42115         duk_bool_t first = 1;
42116         const char *brace1 = "{";
42117         const char *brace2 = "}";
42118         duk_bool_t pushed_loopstack = 0;
42119
42120         if (duk_fb_is_full(fb)) {
42121                 return;
42122         }
42123
42124         duk__print_shared_heaphdr(st, &h->hdr);
42125
42126         if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) {
42127                 brace1 = "[";
42128                 brace2 = "]";
42129         }
42130
42131         if (!h) {
42132                 duk_fb_put_cstring(fb, "NULL");
42133                 goto finished;
42134         }
42135
42136         if (st->depth >= st->depth_limit) {
42137                 const char *subtype = "generic";
42138
42139                 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
42140                         subtype = "compfunc";
42141                 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
42142                         subtype = "natfunc";
42143                 } else if (DUK_HOBJECT_IS_THREAD(h)) {
42144                         subtype = "thread";
42145                 } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
42146                         subtype = "bufobj";
42147                 } else if (DUK_HOBJECT_IS_ARRAY(h)) {
42148                         subtype = "array";
42149                 }
42150                 duk_fb_sprintf(fb, "%sobject/%s %p%s", (const char *) brace1, subtype, (void *) h, (const char *) brace2);
42151                 return;
42152         }
42153
42154         for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) {
42155                 if (st->loop_stack[i] == h) {
42156                         duk_fb_sprintf(fb, "%sLOOP:%p%s", (const char *) brace1, (void *) h, (const char *) brace2);
42157                         return;
42158                 }
42159         }
42160
42161         /* after this, return paths should 'goto finished' for decrement */
42162         st->depth++;
42163
42164         if (st->loop_stack_index >= st->loop_stack_limit) {
42165                 duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", (const char *) brace1, (const char *) brace2);
42166                 goto finished;
42167         }
42168         st->loop_stack[st->loop_stack_index++] = h;
42169         pushed_loopstack = 1;
42170
42171         /*
42172          *  Notation: double underscore used for internal properties which are not
42173          *  stored in the property allocation (e.g. '__valstack').
42174          */
42175
42176         duk_fb_put_cstring(fb, brace1);
42177
42178         if (DUK_HOBJECT_GET_PROPS(NULL, h)) {
42179                 duk_uint32_t a_limit;
42180
42181                 a_limit = DUK_HOBJECT_GET_ASIZE(h);
42182                 if (st->internal) {
42183                         /* dump all allocated entries, unused entries print as 'unused',
42184                          * note that these may extend beyond current 'length' and look
42185                          * a bit funny.
42186                          */
42187                 } else {
42188                         /* leave out trailing 'unused' elements */
42189                         while (a_limit > 0) {
42190                                 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1);
42191                                 if (!DUK_TVAL_IS_UNUSED(tv)) {
42192                                         break;
42193                                 }
42194                                 a_limit--;
42195                         }
42196                 }
42197
42198                 for (i = 0; i < a_limit; i++) {
42199                         tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i);
42200                         DUK__COMMA();
42201                         duk__print_tval(st, tv);
42202                 }
42203                 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) {
42204                         key = DUK_HOBJECT_E_GET_KEY(NULL, h, i);
42205                         if (!key) {
42206                                 continue;
42207                         }
42208                         if (!st->internal && DUK_HSTRING_HAS_HIDDEN(key)) {
42209                                 continue;
42210                         }
42211                         DUK__COMMA();
42212                         duk__print_hstring(st, key, 0);
42213                         duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON);
42214                         if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) {
42215                                 duk_fb_sprintf(fb, "[get:%p,set:%p]",
42216                                                (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get,
42217                                                (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set);
42218                         } else {
42219                                 tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v;
42220                                 duk__print_tval(st, tv);
42221                         }
42222                         if (st->heavy) {
42223                                 duk_fb_sprintf(fb, "<%02lx>", (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i));
42224                         }
42225                 }
42226         }
42227         if (st->internal) {
42228                 if (DUK_HOBJECT_IS_ARRAY(h)) {
42229                         DUK__COMMA(); duk_fb_sprintf(fb, "__array:true");
42230                 }
42231                 if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) {
42232                         DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true");
42233                 }
42234                 if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
42235                         DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true");
42236                 }
42237                 if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
42238                         DUK__COMMA(); duk_fb_sprintf(fb, "__boundfunc:true");
42239                 }
42240                 if (DUK_HOBJECT_HAS_COMPFUNC(h)) {
42241                         DUK__COMMA(); duk_fb_sprintf(fb, "__compfunc:true");
42242                 }
42243                 if (DUK_HOBJECT_HAS_NATFUNC(h)) {
42244                         DUK__COMMA(); duk_fb_sprintf(fb, "__natfunc:true");
42245                 }
42246                 if (DUK_HOBJECT_HAS_BUFOBJ(h)) {
42247                         DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true");
42248                 }
42249                 if (DUK_HOBJECT_IS_THREAD(h)) {
42250                         DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true");
42251                 }
42252                 if (DUK_HOBJECT_HAS_ARRAY_PART(h)) {
42253                         DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true");
42254                 }
42255                 if (DUK_HOBJECT_HAS_STRICT(h)) {
42256                         DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true");
42257                 }
42258                 if (DUK_HOBJECT_HAS_NOTAIL(h)) {
42259                         DUK__COMMA(); duk_fb_sprintf(fb, "__notail:true");
42260                 }
42261                 if (DUK_HOBJECT_HAS_NEWENV(h)) {
42262                         DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true");
42263                 }
42264                 if (DUK_HOBJECT_HAS_NAMEBINDING(h)) {
42265                         DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true");
42266                 }
42267                 if (DUK_HOBJECT_HAS_CREATEARGS(h)) {
42268                         DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true");
42269                 }
42270                 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) {
42271                         DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true");
42272                 }
42273                 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) {
42274                         DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true");
42275                 }
42276                 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) {
42277                         DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true");
42278                 }
42279                 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
42280                         DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufobj:true");
42281                 }
42282                 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) {
42283                         DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true");
42284                 }
42285         }
42286
42287         if (st->internal && DUK_HOBJECT_IS_ARRAY(h)) {
42288                 duk_harray *a = (duk_harray *) h;
42289                 DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) a->length);
42290                 DUK__COMMA(); duk_fb_sprintf(fb, "__length_nonwritable:%ld", (long) a->length_nonwritable);
42291         } else if (st->internal && DUK_HOBJECT_IS_COMPFUNC(h)) {
42292                 duk_hcompfunc *f = (duk_hcompfunc *) h;
42293                 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
42294                 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f));
42295                 DUK__COMMA(); duk_fb_put_cstring(fb, "__lexenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_LEXENV(NULL, f));
42296                 DUK__COMMA(); duk_fb_put_cstring(fb, "__varenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_VARENV(NULL, f));
42297                 DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs);
42298                 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
42299 #if defined(DUK_USE_DEBUGGER_SUPPORT)
42300                 DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld", (long) f->start_line);
42301                 DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line);
42302 #endif
42303                 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
42304                 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f));
42305         } else if (st->internal && DUK_HOBJECT_IS_NATFUNC(h)) {
42306                 duk_hnatfunc *f = (duk_hnatfunc *) h;
42307                 DUK__COMMA(); duk_fb_sprintf(fb, "__func:");
42308                 duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func));
42309                 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
42310                 DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic);
42311         } else if (st->internal && DUK_HOBJECT_IS_DECENV(h)) {
42312                 duk_hdecenv *e = (duk_hdecenv *) h;
42313                 DUK__COMMA(); duk_fb_sprintf(fb, "__thread:"); duk__print_hobject(st, (duk_hobject *) e->thread);
42314                 DUK__COMMA(); duk_fb_sprintf(fb, "__varmap:"); duk__print_hobject(st, (duk_hobject *) e->varmap);
42315                 DUK__COMMA(); duk_fb_sprintf(fb, "__regbase_byteoff:%ld", (long) e->regbase_byteoff);
42316         } else if (st->internal && DUK_HOBJECT_IS_OBJENV(h)) {
42317                 duk_hobjenv *e = (duk_hobjenv *) h;
42318                 DUK__COMMA(); duk_fb_sprintf(fb, "__target:"); duk__print_hobject(st, (duk_hobject *) e->target);
42319                 DUK__COMMA(); duk_fb_sprintf(fb, "__has_this:%ld", (long) e->has_this);
42320 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
42321         } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) {
42322                 duk_hbufobj *b = (duk_hbufobj *) h;
42323                 DUK__COMMA(); duk_fb_sprintf(fb, "__buf:");
42324                 duk__print_hbuffer(st, (duk_hbuffer *) b->buf);
42325                 DUK__COMMA(); duk_fb_sprintf(fb, "__buf_prop:");
42326                 duk__print_hobject(st, (duk_hobject *) b->buf_prop);
42327                 DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset);
42328                 DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length);
42329                 DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift);
42330                 DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type);
42331 #endif
42332         } else if (st->internal && DUK_HOBJECT_IS_PROXY(h)) {
42333                 duk_hproxy *p = (duk_hproxy *) h;
42334                 DUK__COMMA(); duk_fb_sprintf(fb, "__target:");
42335                 duk__print_hobject(st, p->target);
42336                 DUK__COMMA(); duk_fb_sprintf(fb, "__handler:");
42337                 duk__print_hobject(st, p->handler);
42338         } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
42339                 duk_hthread *t = (duk_hthread *) h;
42340                 DUK__COMMA(); duk_fb_sprintf(fb, "__ptr_curr_pc:%p", (void *) t->ptr_curr_pc);
42341                 DUK__COMMA(); duk_fb_sprintf(fb, "__heap:%p", (void *) t->heap);
42342                 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict);
42343                 DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state);
42344                 DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1);
42345                 DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2);
42346                 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
42347                 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack));
42348                 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_alloc_end:%p/%ld", (void *) t->valstack_alloc_end, (long) (t->valstack_alloc_end - t->valstack));
42349                 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack));
42350                 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack));
42351                 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_curr:%p", (void *) t->callstack_curr);
42352                 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_top:%ld", (long) t->callstack_top);
42353                 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_preventcount:%ld", (long) t->callstack_preventcount);
42354                 DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
42355                 DUK__COMMA(); duk_fb_sprintf(fb, "__compile_ctx:%p", (void *) t->compile_ctx);
42356 #if defined(DUK_USE_INTERRUPT_COUNTER)
42357                 DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_counter:%ld", (long) t->interrupt_counter);
42358                 DUK__COMMA(); duk_fb_sprintf(fb, "__interrupt_init:%ld", (long) t->interrupt_init);
42359 #endif
42360
42361                 /* XXX: print built-ins array? */
42362
42363         }
42364 #if defined(DUK_USE_REFERENCE_COUNTING)
42365         if (st->internal) {
42366                 DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h));
42367         }
42368 #endif
42369         if (st->internal) {
42370                 DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld", (long) DUK_HOBJECT_GET_CLASS_NUMBER(h));
42371         }
42372
42373         DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p", (void *) h);  /* own pointer */
42374
42375         /* prototype should be last, for readability */
42376         if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) {
42377                 if (st->follow_proto) {
42378                         DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
42379                 } else {
42380                         DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p", (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
42381                 }
42382         }
42383
42384         duk_fb_put_cstring(fb, brace2);
42385
42386 #if defined(DUK_USE_HOBJECT_HASH_PART)
42387         if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) {
42388                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
42389                 for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) {
42390                         duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i);
42391                         if (i > 0) {
42392                                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA);
42393                         }
42394                         if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) {
42395                                 duk_fb_sprintf(fb, "u");
42396                         } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) {
42397                                 duk_fb_sprintf(fb, "d");
42398                         } else {
42399                                 duk_fb_sprintf(fb, "%ld", (long) h_idx);
42400                         }
42401                 }
42402                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
42403         }
42404 #endif
42405
42406  finished:
42407         st->depth--;
42408         if (pushed_loopstack) {
42409                 st->loop_stack_index--;
42410                 st->loop_stack[st->loop_stack_index] = NULL;
42411         }
42412 }
42413
42414 DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
42415         duk_fixedbuffer *fb = st->fb;
42416         duk_size_t i, n;
42417         duk_uint8_t *p;
42418
42419         if (duk_fb_is_full(fb)) {
42420                 return;
42421         }
42422
42423         /* terminal type: no depth check */
42424
42425         if (!h) {
42426                 duk_fb_put_cstring(fb, "NULL");
42427                 return;
42428         }
42429
42430         if (DUK_HBUFFER_HAS_DYNAMIC(h)) {
42431                 if (DUK_HBUFFER_HAS_EXTERNAL(h)) {
42432                         duk_hbuffer_external *g = (duk_hbuffer_external *) h;
42433                         duk_fb_sprintf(fb, "buffer:external:%p:%ld",
42434                                        (void *) DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(NULL, g),
42435                                        (long) DUK_HBUFFER_EXTERNAL_GET_SIZE(g));
42436                 } else {
42437                         duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
42438                         duk_fb_sprintf(fb, "buffer:dynamic:%p:%ld",
42439                                        (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(NULL, g),
42440                                        (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(g));
42441                 }
42442         } else {
42443                 duk_fb_sprintf(fb, "buffer:fixed:%ld", (long) DUK_HBUFFER_GET_SIZE(h));
42444         }
42445
42446 #if defined(DUK_USE_REFERENCE_COUNTING)
42447         duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
42448 #endif
42449
42450         if (st->hexdump) {
42451                 duk_fb_sprintf(fb, "=[");
42452                 n = DUK_HBUFFER_GET_SIZE(h);
42453                 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(NULL, h);
42454                 for (i = 0; i < n; i++) {
42455                         duk_fb_sprintf(fb, "%02lx", (unsigned long) p[i]);
42456                 }
42457                 duk_fb_sprintf(fb, "]");
42458         }
42459 }
42460
42461 DUK_LOCAL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
42462         duk_fixedbuffer *fb = st->fb;
42463
42464         if (duk_fb_is_full(fb)) {
42465                 return;
42466         }
42467
42468         if (!h) {
42469                 duk_fb_put_cstring(fb, "NULL");
42470                 return;
42471         }
42472
42473         switch (DUK_HEAPHDR_GET_TYPE(h)) {
42474         case DUK_HTYPE_STRING:
42475                 duk__print_hstring(st, (duk_hstring *) h, 1);
42476                 break;
42477         case DUK_HTYPE_OBJECT:
42478                 duk__print_hobject(st, (duk_hobject *) h);
42479                 break;
42480         case DUK_HTYPE_BUFFER:
42481                 duk__print_hbuffer(st, (duk_hbuffer *) h);
42482                 break;
42483         default:
42484                 duk_fb_sprintf(fb, "[unknown htype %ld]", (long) DUK_HEAPHDR_GET_TYPE(h));
42485                 break;
42486         }
42487 }
42488
42489 DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
42490         duk_fixedbuffer *fb = st->fb;
42491
42492         if (duk_fb_is_full(fb)) {
42493                 return;
42494         }
42495
42496         /* depth check is done when printing an actual type */
42497
42498         if (st->heavy) {
42499                 duk_fb_sprintf(fb, "(%p)", (void *) tv);
42500         }
42501
42502         if (!tv) {
42503                 duk_fb_put_cstring(fb, "NULL");
42504                 return;
42505         }
42506
42507         if (st->binary) {
42508                 duk_size_t i;
42509                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
42510                 for (i = 0; i < (duk_size_t) sizeof(*tv); i++) {
42511                         duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)tv)[i]);
42512                 }
42513                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
42514         }
42515
42516         if (st->heavy) {
42517                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
42518         }
42519         switch (DUK_TVAL_GET_TAG(tv)) {
42520         case DUK_TAG_UNDEFINED: {
42521                 duk_fb_put_cstring(fb, "undefined");
42522                 break;
42523         }
42524         case DUK_TAG_UNUSED: {
42525                 duk_fb_put_cstring(fb, "unused");
42526                 break;
42527         }
42528         case DUK_TAG_NULL: {
42529                 duk_fb_put_cstring(fb, "null");
42530                 break;
42531         }
42532         case DUK_TAG_BOOLEAN: {
42533                 duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false");
42534                 break;
42535         }
42536         case DUK_TAG_STRING: {
42537                 /* Note: string is a terminal heap object, so no depth check here */
42538                 duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1);
42539                 break;
42540         }
42541         case DUK_TAG_OBJECT: {
42542                 duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv));
42543                 break;
42544         }
42545         case DUK_TAG_BUFFER: {
42546                 duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv));
42547                 break;
42548         }
42549         case DUK_TAG_POINTER: {
42550                 duk_fb_sprintf(fb, "pointer:%p", (void *) DUK_TVAL_GET_POINTER(tv));
42551                 break;
42552         }
42553         case DUK_TAG_LIGHTFUNC: {
42554                 duk_c_function func;
42555                 duk_small_uint_t lf_flags;
42556
42557                 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
42558                 duk_fb_sprintf(fb, "lightfunc:");
42559                 duk_fb_put_funcptr(fb, (duk_uint8_t *) &func, sizeof(func));
42560                 duk_fb_sprintf(fb, ":%04lx", (long) lf_flags);
42561                 break;
42562         }
42563 #if defined(DUK_USE_FASTINT)
42564         case DUK_TAG_FASTINT:
42565                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
42566                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
42567                 duk_fb_sprintf(fb, "%.18g_F", (double) DUK_TVAL_GET_NUMBER(tv));
42568                 break;
42569 #endif
42570         default: {
42571                 /* IEEE double is approximately 16 decimal digits; print a couple extra */
42572                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
42573                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
42574                 duk_fb_sprintf(fb, "%.18g", (double) DUK_TVAL_GET_NUMBER(tv));
42575                 break;
42576         }
42577         }
42578         if (st->heavy) {
42579                 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
42580         }
42581 }
42582
42583 DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) {
42584         duk_fixedbuffer *fb = st->fb;
42585         duk_small_int_t op;
42586         const char *op_name;
42587
42588         op = (duk_small_int_t) DUK_DEC_OP(ins);
42589         op_name = duk__bc_optab[op];
42590
42591         /* XXX: option to fix opcode length so it lines up nicely */
42592
42593         if (op == DUK_OP_JUMP) {
42594                 duk_int_t diff1 = (duk_int_t) (DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS);  /* from next pc */
42595                 duk_int_t diff2 = diff1 + 1;                                          /* from curr pc */
42596
42597                 duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)",
42598                                (const char *) op_name, (long) diff1,
42599                                (int) (diff2 >= 0 ? '+' : '-'),  /* char format: use int */
42600                                (long) (diff2 >= 0 ? diff2 : -diff2));
42601         } else {
42602                 duk_fb_sprintf(fb, "%s %ld, %ld, %ld",
42603                                (const char *) op_name, (long) DUK_DEC_A(ins),
42604                                (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
42605         }
42606 }
42607
42608 DUK_LOCAL void duk__print_opcode(duk__dprint_state *st, duk_small_int_t opcode) {
42609         duk_fixedbuffer *fb = st->fb;
42610
42611         if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) {
42612                 duk_fb_sprintf(fb, "?(%ld)", (long) opcode);
42613         } else {
42614                 duk_fb_sprintf(fb, "%s", (const char *) duk__bc_optab[opcode]);
42615         }
42616 }
42617
42618 DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap) {
42619         duk_fixedbuffer fb;
42620         const char *p = format;
42621         const char *p_end = p + DUK_STRLEN(format);
42622         duk_int_t retval;
42623
42624         duk_memzero(&fb, sizeof(fb));
42625         fb.buffer = (duk_uint8_t *) str;
42626         fb.length = size;
42627         fb.offset = 0;
42628         fb.truncated = 0;
42629
42630         while (p < p_end) {
42631                 char ch = *p++;
42632                 const char *p_begfmt = NULL;
42633                 duk_bool_t got_exclamation = 0;
42634                 duk_bool_t got_long = 0;  /* %lf, %ld etc */
42635                 duk__dprint_state st;
42636
42637                 if (ch != DUK_ASC_PERCENT) {
42638                         duk_fb_put_byte(&fb, (duk_uint8_t) ch);
42639                         continue;
42640                 }
42641
42642                 /*
42643                  *  Format tag parsing.  Since we don't understand all the
42644                  *  possible format tags allowed, we just scan for a terminating
42645                  *  specifier and keep track of relevant modifiers that we do
42646                  *  understand.  See man 3 printf.
42647                  */
42648
42649                 duk_memzero(&st, sizeof(st));
42650                 st.fb = &fb;
42651                 st.depth = 0;
42652                 st.depth_limit = 1;
42653                 st.loop_stack_index = 0;
42654                 st.loop_stack_limit = DUK__LOOP_STACK_DEPTH;
42655
42656                 p_begfmt = p - 1;
42657                 while (p < p_end) {
42658                         ch = *p++;
42659
42660                         if (ch == DUK_ASC_STAR) {
42661                                 /* unsupported: would consume multiple args */
42662                                 goto format_error;
42663                         } else if (ch == DUK_ASC_PERCENT) {
42664                                 duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT);
42665                                 break;
42666                         } else if (ch == DUK_ASC_EXCLAMATION) {
42667                                 got_exclamation = 1;
42668                         } else if (!got_exclamation && ch == DUK_ASC_LC_L) {
42669                                 got_long = 1;
42670                         } else if (got_exclamation && ch == DUK_ASC_LC_D) {
42671                                 st.depth_limit = DUK__DEEP_DEPTH_LIMIT;
42672                         } else if (got_exclamation && ch == DUK_ASC_LC_P) {
42673                                 st.follow_proto = 1;
42674                         } else if (got_exclamation && ch == DUK_ASC_LC_I) {
42675                                 st.internal = 1;
42676                         } else if (got_exclamation && ch == DUK_ASC_LC_X) {
42677                                 st.hexdump = 1;
42678                         } else if (got_exclamation && ch == DUK_ASC_LC_H) {
42679                                 st.heavy = 1;
42680                         } else if (got_exclamation && ch == DUK_ASC_ATSIGN) {
42681                                 st.pointer = 1;
42682                         } else if (got_exclamation && ch == DUK_ASC_HASH) {
42683                                 st.binary = 1;
42684                         } else if (got_exclamation && ch == DUK_ASC_UC_T) {
42685                                 duk_tval *t = va_arg(ap, duk_tval *);
42686                                 if (st.pointer && !st.heavy) {
42687                                         duk_fb_sprintf(&fb, "(%p)", (void *) t);
42688                                 }
42689                                 duk__print_tval(&st, t);
42690                                 break;
42691                         } else if (got_exclamation && ch == DUK_ASC_UC_O) {
42692                                 duk_heaphdr *t = va_arg(ap, duk_heaphdr *);
42693                                 if (st.pointer && !st.heavy) {
42694                                         duk_fb_sprintf(&fb, "(%p)", (void *) t);
42695                                 }
42696                                 duk__print_heaphdr(&st, t);
42697                                 break;
42698                         } else if (got_exclamation && ch == DUK_ASC_UC_I) {
42699                                 duk_instr_t t = va_arg(ap, duk_instr_t);
42700                                 duk__print_instr(&st, t);
42701                                 break;
42702                         } else if (got_exclamation && ch == DUK_ASC_UC_C) {
42703                                 long t = va_arg(ap, long);
42704                                 duk__print_opcode(&st, (duk_small_int_t) t);
42705                                 break;
42706                         } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) {
42707                                 char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH];
42708                                 duk_size_t fmtlen;
42709
42710                                 DUK_ASSERT(p >= p_begfmt);
42711                                 fmtlen = (duk_size_t) (p - p_begfmt);
42712                                 if (fmtlen >= sizeof(fmtbuf)) {
42713                                         /* format is too large, abort */
42714                                         goto format_error;
42715                                 }
42716                                 duk_memzero(fmtbuf, sizeof(fmtbuf));
42717                                 duk_memcpy(fmtbuf, p_begfmt, fmtlen);
42718
42719                                 /* assume exactly 1 arg, which is why '*' is forbidden; arg size still
42720                                  * depends on type though.
42721                                  */
42722
42723                                 if (ch == DUK_ASC_LC_F || ch == DUK_ASC_LC_G || ch == DUK_ASC_LC_E) {
42724                                         /* %f and %lf both consume a 'long' */
42725                                         double arg = va_arg(ap, double);
42726                                         duk_fb_sprintf(&fb, fmtbuf, arg);
42727                                 } else if (ch == DUK_ASC_LC_D && got_long) {
42728                                         /* %ld */
42729                                         long arg = va_arg(ap, long);
42730                                         duk_fb_sprintf(&fb, fmtbuf, arg);
42731                                 } else if (ch == DUK_ASC_LC_D) {
42732                                         /* %d; only 16 bits are guaranteed */
42733                                         int arg = va_arg(ap, int);
42734                                         duk_fb_sprintf(&fb, fmtbuf, arg);
42735                                 } else if (ch == DUK_ASC_LC_U && got_long) {
42736                                         /* %lu */
42737                                         unsigned long arg = va_arg(ap, unsigned long);
42738                                         duk_fb_sprintf(&fb, fmtbuf, arg);
42739                                 } else if (ch == DUK_ASC_LC_U) {
42740                                         /* %u; only 16 bits are guaranteed */
42741                                         unsigned int arg = va_arg(ap, unsigned int);
42742                                         duk_fb_sprintf(&fb, fmtbuf, arg);
42743                                 } else if (ch == DUK_ASC_LC_X && got_long) {
42744                                         /* %lx */
42745                                         unsigned long arg = va_arg(ap, unsigned long);
42746                                         duk_fb_sprintf(&fb, fmtbuf, arg);
42747                                 } else if (ch == DUK_ASC_LC_X) {
42748                                         /* %x; only 16 bits are guaranteed */
42749                                         unsigned int arg = va_arg(ap, unsigned int);
42750                                         duk_fb_sprintf(&fb, fmtbuf, arg);
42751                                 } else if (ch == DUK_ASC_LC_S) {
42752                                         /* %s */
42753                                         const char *arg = va_arg(ap, const char *);
42754                                         if (arg == NULL) {
42755                                                 /* '%s' and NULL is not portable, so special case
42756                                                  * it for debug printing.
42757                                                  */
42758                                                 duk_fb_sprintf(&fb, "NULL");
42759                                         } else {
42760                                                 duk_fb_sprintf(&fb, fmtbuf, arg);
42761                                         }
42762                                 } else if (ch == DUK_ASC_LC_P) {
42763                                         /* %p */
42764                                         void *arg = va_arg(ap, void *);
42765                                         if (arg == NULL) {
42766                                                 /* '%p' and NULL is portable, but special case it
42767                                                  * anyway to get a standard NULL marker in logs.
42768                                                  */
42769                                                 duk_fb_sprintf(&fb, "NULL");
42770                                         } else {
42771                                                 duk_fb_sprintf(&fb, fmtbuf, arg);
42772                                         }
42773                                 } else if (ch == DUK_ASC_LC_C) {
42774                                         /* '%c', passed concretely as int */
42775                                         int arg = va_arg(ap, int);
42776                                         duk_fb_sprintf(&fb, fmtbuf, arg);
42777                                 } else {
42778                                         /* Should not happen. */
42779                                         duk_fb_sprintf(&fb, "INVALID-FORMAT(%s)", (const char *) fmtbuf);
42780                                 }
42781                                 break;
42782                         } else {
42783                                 /* ignore */
42784                         }
42785                 }
42786         }
42787         goto done;
42788
42789  format_error:
42790         duk_fb_put_cstring(&fb, "FMTERR");
42791         /* fall through */
42792
42793  done:
42794         retval = (duk_int_t) fb.offset;
42795         duk_fb_put_byte(&fb, (duk_uint8_t) 0);
42796
42797         /* return total chars written excluding terminator */
42798         return retval;
42799 }
42800
42801 #if 0  /*unused*/
42802 DUK_INTERNAL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...) {
42803         duk_int_t retval;
42804         va_list ap;
42805         va_start(ap, format);
42806         retval = duk_debug_vsnprintf(str, size, format, ap);
42807         va_end(ap);
42808         return retval;
42809 }
42810 #endif
42811
42812 /* Formatting function pointers is tricky: there is no standard pointer for
42813  * function pointers and the size of a function pointer may depend on the
42814  * specific pointer type.  This helper formats a function pointer based on
42815  * its memory layout to get something useful on most platforms.
42816  */
42817 DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size) {
42818         duk_size_t i;
42819         duk_uint8_t *p = (duk_uint8_t *) buf;
42820         duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1);
42821
42822         DUK_ASSERT(buf != NULL);
42823         duk_memzero(buf, buf_size);
42824
42825         for (i = 0; i < fptr_size; i++) {
42826                 duk_int_t left = (duk_int_t) (p_end - p);
42827                 duk_uint8_t ch;
42828                 if (left <= 0) {
42829                         break;
42830                 }
42831
42832                 /* Quite approximate but should be useful for little and big endian. */
42833 #if defined(DUK_USE_INTEGER_BE)
42834                 ch = fptr[i];
42835 #else
42836                 ch = fptr[fptr_size - 1 - i];
42837 #endif
42838                 p += DUK_SNPRINTF((char *) p, (duk_size_t) left, "%02lx", (unsigned long) ch);
42839         }
42840 }
42841
42842 #endif  /* DUK_USE_DEBUG */
42843
42844 /* automatic undefs */
42845 #undef DUK__ALLOWED_STANDARD_SPECIFIERS
42846 #undef DUK__COMMA
42847 #undef DUK__DEEP_DEPTH_LIMIT
42848 #undef DUK__LOOP_STACK_DEPTH
42849 #undef DUK__MAX_FORMAT_TAG_LENGTH
42850 #line 1 "duk_debugger.c"
42851 /*
42852  *  Duktape debugger
42853  */
42854
42855 /* #include duk_internal.h -> already included */
42856
42857 #if defined(DUK_USE_DEBUGGER_SUPPORT)
42858
42859 /*
42860  *  Assert helpers
42861  */
42862
42863 #if defined(DUK_USE_ASSERTIONS)
42864 #define DUK__DBG_TPORT_ENTER() do { \
42865                 DUK_ASSERT(heap->dbg_calling_transport == 0); \
42866                 heap->dbg_calling_transport = 1; \
42867         } while (0)
42868 #define DUK__DBG_TPORT_EXIT() do { \
42869                 DUK_ASSERT(heap->dbg_calling_transport == 1); \
42870                 heap->dbg_calling_transport = 0; \
42871         } while (0)
42872 #else
42873 #define DUK__DBG_TPORT_ENTER() do {} while (0)
42874 #define DUK__DBG_TPORT_EXIT() do {} while (0)
42875 #endif
42876
42877 /*
42878  *  Helper structs
42879  */
42880
42881 typedef union {
42882         void *p;
42883         duk_uint_t b[1];
42884         /* Use b[] to access the size of the union, which is strictly not
42885          * correct.  Can't use fixed size unless there's feature detection
42886          * for pointer byte size.
42887          */
42888 } duk__ptr_union;
42889
42890 /*
42891  *  Detach handling
42892  */
42893
42894 #define DUK__SET_CONN_BROKEN(thr,reason) do { \
42895                 /* For now shared handler is fine. */ \
42896                 duk__debug_do_detach1((thr)->heap, (reason)); \
42897         } while (0)
42898
42899 DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
42900         /* Can be called multiple times with no harm.  Mark the transport
42901          * bad (dbg_read_cb == NULL) and clear state except for the detached
42902          * callback and the udata field.  The detached callback is delayed
42903          * to the message loop so that it can be called between messages;
42904          * this avoids corner cases related to immediate debugger reattach
42905          * inside the detached callback.
42906          */
42907
42908         if (heap->dbg_detaching) {
42909                 DUK_D(DUK_DPRINT("debugger already detaching, ignore detach1"));
42910                 return;
42911         }
42912
42913         DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken"));
42914
42915         heap->dbg_detaching = 1;  /* prevent multiple in-progress detaches */
42916
42917         if (heap->dbg_write_cb != NULL) {
42918                 duk_hthread *thr;
42919
42920                 thr = heap->heap_thread;
42921                 DUK_ASSERT(thr != NULL);
42922
42923                 duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING);
42924                 duk_debug_write_int(thr, reason);
42925                 duk_debug_write_eom(thr);
42926         }
42927
42928         heap->dbg_read_cb = NULL;
42929         heap->dbg_write_cb = NULL;
42930         heap->dbg_peek_cb = NULL;
42931         heap->dbg_read_flush_cb = NULL;
42932         heap->dbg_write_flush_cb = NULL;
42933         heap->dbg_request_cb = NULL;
42934         /* heap->dbg_detached_cb: keep */
42935         /* heap->dbg_udata: keep */
42936         /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */
42937         heap->dbg_state_dirty = 0;
42938         heap->dbg_force_restart = 0;
42939         heap->dbg_pause_flags = 0;
42940         heap->dbg_pause_act = NULL;
42941         heap->dbg_pause_startline = 0;
42942         heap->dbg_have_next_byte = 0;
42943         duk_debug_clear_paused(heap);  /* XXX: some overlap with field inits above */
42944         heap->dbg_state_dirty = 0;     /* XXX: clear_paused sets dirty; rework? */
42945
42946         /* Ensure there are no stale active breakpoint pointers.
42947          * Breakpoint list is currently kept - we could empty it
42948          * here but we'd need to handle refcounts correctly, and
42949          * we'd need a 'thr' reference for that.
42950          *
42951          * XXX: clear breakpoint on either attach or detach?
42952          */
42953         heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
42954 }
42955
42956 DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
42957         duk_debug_detached_function detached_cb;
42958         void *detached_udata;
42959         duk_hthread *thr;
42960
42961         thr = heap->heap_thread;
42962         if (thr == NULL) {
42963                 DUK_ASSERT(heap->dbg_detached_cb == NULL);
42964                 return;
42965         }
42966
42967         /* Safe to call multiple times. */
42968
42969         detached_cb = heap->dbg_detached_cb;
42970         detached_udata = heap->dbg_udata;
42971         heap->dbg_detached_cb = NULL;
42972         heap->dbg_udata = NULL;
42973
42974         if (detached_cb) {
42975                 /* Careful here: state must be wiped before the call
42976                  * so that we can cleanly handle a re-attach from
42977                  * inside the callback.
42978                  */
42979                 DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
42980                 detached_cb(thr, detached_udata);
42981         }
42982
42983         heap->dbg_detaching = 0;
42984 }
42985
42986 DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
42987         duk__debug_do_detach1(heap, 0);
42988         duk__debug_do_detach2(heap);
42989 }
42990
42991 /* Called on a read/write error: NULL all callbacks except the detached
42992  * callback so that we never accidentally call them after a read/write
42993  * error has been indicated.  This is especially important for the transport
42994  * I/O callbacks to fulfill guaranteed callback semantics.
42995  */
42996 DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
42997         duk_heap *heap;
42998
42999         DUK_ASSERT(thr != NULL);
43000
43001         heap = thr->heap;
43002         DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached"));
43003         heap->dbg_read_cb = NULL;
43004         heap->dbg_write_cb = NULL;  /* this is especially critical to avoid another write call in detach1() */
43005         heap->dbg_peek_cb = NULL;
43006         heap->dbg_read_flush_cb = NULL;
43007         heap->dbg_write_flush_cb = NULL;
43008         heap->dbg_request_cb = NULL;
43009         /* keep heap->dbg_detached_cb */
43010 }
43011
43012 /*
43013  *  Pause handling
43014  */
43015
43016 DUK_LOCAL void duk__debug_set_pause_state(duk_hthread *thr, duk_heap *heap, duk_small_uint_t pause_flags) {
43017         duk_uint_fast32_t line;
43018
43019         line = duk_debug_curr_line(thr);
43020         if (line == 0) {
43021                 /* No line info for current function. */
43022                 duk_small_uint_t updated_flags;
43023
43024                 updated_flags = pause_flags & ~(DUK_PAUSE_FLAG_LINE_CHANGE);
43025                 DUK_D(DUK_DPRINT("no line info for current activation, disable line-based pause flags: 0x%08lx -> 0x%08lx",
43026                                  (long) pause_flags, (long) updated_flags));
43027                 pause_flags = updated_flags;
43028         }
43029
43030         heap->dbg_pause_flags = pause_flags;
43031         heap->dbg_pause_act = thr->callstack_curr;
43032         heap->dbg_pause_startline = (duk_uint32_t) line;
43033         heap->dbg_state_dirty = 1;
43034
43035         DUK_D(DUK_DPRINT("set state for automatic pause triggers, flags=0x%08lx, act=%p, startline=%ld",
43036                          (long) heap->dbg_pause_flags, (void *) heap->dbg_pause_act,
43037                          (long) heap->dbg_pause_startline));
43038 }
43039
43040 /*
43041  *  Debug connection peek and flush primitives
43042  */
43043
43044 DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
43045         duk_heap *heap;
43046         duk_bool_t ret;
43047
43048         DUK_ASSERT(thr != NULL);
43049         heap = thr->heap;
43050         DUK_ASSERT(heap != NULL);
43051
43052         if (heap->dbg_read_cb == NULL) {
43053                 DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)"));
43054                 return 0;
43055         }
43056         if (heap->dbg_peek_cb == NULL) {
43057                 DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)"));
43058                 return 0;
43059         }
43060
43061         DUK__DBG_TPORT_ENTER();
43062         ret = (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
43063         DUK__DBG_TPORT_EXIT();
43064         return ret;
43065 }
43066
43067 DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
43068         duk_heap *heap;
43069
43070         DUK_ASSERT(thr != NULL);
43071         heap = thr->heap;
43072         DUK_ASSERT(heap != NULL);
43073
43074         if (heap->dbg_read_cb == NULL) {
43075                 DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore"));
43076                 return;
43077         }
43078         if (heap->dbg_read_flush_cb == NULL) {
43079                 DUK_DD(DUK_DDPRINT("no read flush callback, ignore"));
43080                 return;
43081         }
43082
43083         DUK__DBG_TPORT_ENTER();
43084         heap->dbg_read_flush_cb(heap->dbg_udata);
43085         DUK__DBG_TPORT_EXIT();
43086 }
43087
43088 DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
43089         duk_heap *heap;
43090
43091         DUK_ASSERT(thr != NULL);
43092         heap = thr->heap;
43093         DUK_ASSERT(heap != NULL);
43094
43095         if (heap->dbg_read_cb == NULL) {
43096                 DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore"));
43097                 return;
43098         }
43099         if (heap->dbg_write_flush_cb == NULL) {
43100                 DUK_DD(DUK_DDPRINT("no write flush callback, ignore"));
43101                 return;
43102         }
43103
43104         DUK__DBG_TPORT_ENTER();
43105         heap->dbg_write_flush_cb(heap->dbg_udata);
43106         DUK__DBG_TPORT_EXIT();
43107 }
43108
43109 /*
43110  *  Debug connection skip primitives
43111  */
43112
43113 /* Skip fully. */
43114 DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) {
43115         duk_uint8_t dummy[64];
43116         duk_size_t now;
43117
43118         DUK_ASSERT(thr != NULL);
43119
43120         while (length > 0) {
43121                 now = (length > sizeof(dummy) ? sizeof(dummy) : length);
43122                 duk_debug_read_bytes(thr, dummy, now);
43123                 length -= now;
43124         }
43125 }
43126
43127 DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) {
43128         DUK_ASSERT(thr != NULL);
43129
43130         (void) duk_debug_read_byte(thr);
43131 }
43132
43133 /*
43134  *  Debug connection read primitives
43135  */
43136
43137 /* Peek ahead in the stream one byte. */
43138 DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) {
43139         /* It is important not to call this if the last byte read was an EOM.
43140          * Reading ahead in this scenario would cause unnecessary blocking if
43141          * another message is not available.
43142          */
43143
43144         duk_uint8_t x;
43145
43146         x = duk_debug_read_byte(thr);
43147         thr->heap->dbg_have_next_byte = 1;
43148         thr->heap->dbg_next_byte = x;
43149         return x;
43150 }
43151
43152 /* Read fully. */
43153 DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) {
43154         duk_heap *heap;
43155         duk_uint8_t *p;
43156         duk_size_t left;
43157         duk_size_t got;
43158
43159         DUK_ASSERT(thr != NULL);
43160         heap = thr->heap;
43161         DUK_ASSERT(heap != NULL);
43162         DUK_ASSERT(data != NULL);
43163
43164         if (heap->dbg_read_cb == NULL) {
43165                 DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));
43166                 goto fail;
43167         }
43168
43169         /* NOTE: length may be zero */
43170         p = data;
43171         if (length >= 1 && heap->dbg_have_next_byte) {
43172                 heap->dbg_have_next_byte = 0;
43173                 *p++ = heap->dbg_next_byte;
43174         }
43175         for (;;) {
43176                 left = (duk_size_t) ((data + length) - p);
43177                 if (left == 0) {
43178                         break;
43179                 }
43180                 DUK_ASSERT(heap->dbg_read_cb != NULL);
43181                 DUK_ASSERT(left >= 1);
43182 #if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
43183                 left = 1;
43184 #endif
43185                 DUK__DBG_TPORT_ENTER();
43186                 got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
43187                 DUK__DBG_TPORT_EXIT();
43188
43189                 if (got == 0 || got > left) {
43190                         DUK_D(DUK_DPRINT("connection error during read, return zero data"));
43191                         duk__debug_null_most_callbacks(thr);  /* avoid calling write callback in detach1() */
43192                         DUK__SET_CONN_BROKEN(thr, 1);
43193                         goto fail;
43194                 }
43195                 p += got;
43196         }
43197         return;
43198
43199  fail:
43200         duk_memzero((void *) data, (size_t) length);
43201 }
43202
43203 DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
43204         duk_uint8_t x;
43205
43206         x = 0;  /* just in case callback is broken and won't write 'x' */
43207         duk_debug_read_bytes(thr, &x, 1);
43208         return x;
43209 }
43210
43211 DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
43212         duk_uint8_t buf[4];
43213
43214         DUK_ASSERT(thr != NULL);
43215
43216         duk_debug_read_bytes(thr, buf, 4);
43217         return ((duk_uint32_t) buf[0] << 24) |
43218                ((duk_uint32_t) buf[1] << 16) |
43219                ((duk_uint32_t) buf[2] << 8) |
43220                (duk_uint32_t) buf[3];
43221 }
43222
43223 DUK_LOCAL duk_int32_t duk__debug_read_int32_raw(duk_hthread *thr) {
43224         return (duk_int32_t) duk__debug_read_uint32_raw(thr);
43225 }
43226
43227 DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) {
43228         duk_uint8_t buf[2];
43229
43230         DUK_ASSERT(thr != NULL);
43231
43232         duk_debug_read_bytes(thr, buf, 2);
43233         return ((duk_uint16_t) buf[0] << 8) |
43234                (duk_uint16_t) buf[1];
43235 }
43236
43237 DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
43238         duk_small_uint_t x;
43239         duk_small_uint_t t;
43240
43241         DUK_ASSERT(thr != NULL);
43242
43243         x = duk_debug_read_byte(thr);
43244         if (x >= 0xc0) {
43245                 t = duk_debug_read_byte(thr);
43246                 return (duk_int32_t) (((x - 0xc0) << 8) + t);
43247         } else if (x >= 0x80) {
43248                 return (duk_int32_t) (x - 0x80);
43249         } else if (x == DUK_DBG_IB_INT4) {
43250                 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
43251         }
43252
43253         DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
43254         DUK__SET_CONN_BROKEN(thr, 1);
43255         return 0;
43256 }
43257
43258 DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
43259         duk_uint8_t buf[31];
43260         duk_uint8_t *p;
43261
43262         if (len <= sizeof(buf)) {
43263                 duk_debug_read_bytes(thr, buf, (duk_size_t) len);
43264                 duk_push_lstring(thr, (const char *) buf, (duk_size_t) len);
43265         } else {
43266                 p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len);  /* zero for paranoia */
43267                 DUK_ASSERT(p != NULL);
43268                 duk_debug_read_bytes(thr, p, (duk_size_t) len);
43269                 (void) duk_buffer_to_string(thr, -1);  /* Safety relies on debug client, which is OK. */
43270         }
43271
43272         return duk_require_hstring(thr, -1);
43273 }
43274
43275 DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
43276         duk_small_uint_t x;
43277         duk_uint32_t len;
43278
43279         DUK_ASSERT(thr != NULL);
43280
43281         x = duk_debug_read_byte(thr);
43282         if (x >= 0x60 && x <= 0x7f) {
43283                 /* For short strings, use a fixed temp buffer. */
43284                 len = (duk_uint32_t) (x - 0x60);
43285         } else if (x == DUK_DBG_IB_STR2) {
43286                 len = (duk_uint32_t) duk__debug_read_uint16_raw(thr);
43287         } else if (x == DUK_DBG_IB_STR4) {
43288                 len = (duk_uint32_t) duk__debug_read_uint32_raw(thr);
43289         } else {
43290                 goto fail;
43291         }
43292
43293         return duk__debug_read_hstring_raw(thr, len);
43294
43295  fail:
43296         DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
43297         DUK__SET_CONN_BROKEN(thr, 1);
43298         duk_push_hstring_empty(thr);  /* always push some string */
43299         return duk_require_hstring(thr, -1);
43300 }
43301
43302 DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
43303         duk_uint8_t *p;
43304
43305         p = (duk_uint8_t *) duk_push_fixed_buffer(thr, (duk_size_t) len);  /* zero for paranoia */
43306         DUK_ASSERT(p != NULL);
43307         duk_debug_read_bytes(thr, p, (duk_size_t) len);
43308
43309         return duk_require_hbuffer(thr, -1);
43310 }
43311
43312 DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
43313         duk_small_uint_t x;
43314         duk__ptr_union pu;
43315
43316         DUK_ASSERT(thr != NULL);
43317
43318         x = duk_debug_read_byte(thr);
43319         if (x != sizeof(pu)) {
43320                 goto fail;
43321         }
43322         duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu));
43323 #if defined(DUK_USE_INTEGER_LE)
43324         duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
43325 #endif
43326         return (void *) pu.p;
43327
43328  fail:
43329         DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer"));
43330         DUK__SET_CONN_BROKEN(thr, 1);
43331         return (void *) NULL;
43332 }
43333
43334 DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) {
43335         duk_double_union du;
43336
43337         DUK_ASSERT(sizeof(du.uc) == 8);
43338         duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc));
43339         DUK_DBLUNION_DOUBLE_NTOH(&du);
43340         return du.d;
43341 }
43342
43343 #if 0
43344 DUK_INTERNAL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr) {
43345         duk_small_uint_t x;
43346
43347         DUK_ASSERT(thr != NULL);
43348
43349         x = duk_debug_read_byte(thr);
43350         if (x != DUK_DBG_IB_HEAPPTR) {
43351                 goto fail;
43352         }
43353
43354         return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
43355
43356  fail:
43357         DUK_D(DUK_DPRINT("debug connection error: failed to decode heapptr"));
43358         DUK__SET_CONN_BROKEN(thr, 1);
43359         return NULL;
43360 }
43361 #endif
43362
43363 DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) {
43364         duk_small_uint_t x;
43365
43366         DUK_ASSERT(thr != NULL);
43367
43368         x = duk_debug_read_byte(thr);
43369         switch (x) {
43370         case DUK_DBG_IB_OBJECT:
43371         case DUK_DBG_IB_POINTER:
43372         case DUK_DBG_IB_HEAPPTR:
43373                 /* Accept any pointer-like value; for 'object' dvalue, read
43374                  * and ignore the class number.
43375                  */
43376                 if (x == DUK_DBG_IB_OBJECT) {
43377                         duk_debug_skip_byte(thr);
43378                 }
43379                 break;
43380         default:
43381                 goto fail;
43382         }
43383
43384         return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
43385
43386  fail:
43387         DUK_D(DUK_DPRINT("debug connection error: failed to decode any pointer (object, pointer, heapptr)"));
43388         DUK__SET_CONN_BROKEN(thr, 1);
43389         return NULL;
43390 }
43391
43392 DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
43393         duk_uint8_t x;
43394         duk_uint_t t;
43395         duk_uint32_t len;
43396
43397         DUK_ASSERT(thr != NULL);
43398
43399         x = duk_debug_read_byte(thr);
43400
43401         if (x >= 0xc0) {
43402                 t = (duk_uint_t) (x - 0xc0);
43403                 t = (t << 8) + duk_debug_read_byte(thr);
43404                 duk_push_uint(thr, (duk_uint_t) t);
43405                 goto return_ptr;
43406         }
43407         if (x >= 0x80) {
43408                 duk_push_uint(thr, (duk_uint_t) (x - 0x80));
43409                 goto return_ptr;
43410         }
43411         if (x >= 0x60) {
43412                 len = (duk_uint32_t) (x - 0x60);
43413                 duk__debug_read_hstring_raw(thr, len);
43414                 goto return_ptr;
43415         }
43416
43417         switch (x) {
43418         case DUK_DBG_IB_INT4: {
43419                 duk_int32_t i = duk__debug_read_int32_raw(thr);
43420                 duk_push_i32(thr, i);
43421                 break;
43422         }
43423         case DUK_DBG_IB_STR4: {
43424                 len = duk__debug_read_uint32_raw(thr);
43425                 duk__debug_read_hstring_raw(thr, len);
43426                 break;
43427         }
43428         case DUK_DBG_IB_STR2: {
43429                 len = duk__debug_read_uint16_raw(thr);
43430                 duk__debug_read_hstring_raw(thr, len);
43431                 break;
43432         }
43433         case DUK_DBG_IB_BUF4: {
43434                 len = duk__debug_read_uint32_raw(thr);
43435                 duk__debug_read_hbuffer_raw(thr, len);
43436                 break;
43437         }
43438         case DUK_DBG_IB_BUF2: {
43439                 len = duk__debug_read_uint16_raw(thr);
43440                 duk__debug_read_hbuffer_raw(thr, len);
43441                 break;
43442         }
43443         case DUK_DBG_IB_UNDEFINED: {
43444                 duk_push_undefined(thr);
43445                 break;
43446         }
43447         case DUK_DBG_IB_NULL: {
43448                 duk_push_null(thr);
43449                 break;
43450         }
43451         case DUK_DBG_IB_TRUE: {
43452                 duk_push_true(thr);
43453                 break;
43454         }
43455         case DUK_DBG_IB_FALSE: {
43456                 duk_push_false(thr);
43457                 break;
43458         }
43459         case DUK_DBG_IB_NUMBER: {
43460                 duk_double_t d;
43461                 d = duk__debug_read_double_raw(thr);
43462                 duk_push_number(thr, d);
43463                 break;
43464         }
43465         case DUK_DBG_IB_OBJECT: {
43466                 duk_heaphdr *h;
43467                 duk_debug_skip_byte(thr);
43468                 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
43469                 duk_push_heapptr(thr, (void *) h);
43470                 break;
43471         }
43472         case DUK_DBG_IB_POINTER: {
43473                 void *ptr;
43474                 ptr = duk__debug_read_pointer_raw(thr);
43475                 duk_push_pointer(thr, ptr);
43476                 break;
43477         }
43478         case DUK_DBG_IB_LIGHTFUNC: {
43479                 /* XXX: Not needed for now, so not implemented.  Note that
43480                  * function pointers may have different size/layout than
43481                  * a void pointer.
43482                  */
43483                 DUK_D(DUK_DPRINT("reading lightfunc values unimplemented"));
43484                 goto fail;
43485         }
43486         case DUK_DBG_IB_HEAPPTR: {
43487                 duk_heaphdr *h;
43488                 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
43489                 duk_push_heapptr(thr, (void *) h);
43490                 break;
43491         }
43492         case DUK_DBG_IB_UNUSED:  /* unused: not accepted in inbound messages */
43493         default:
43494                 goto fail;
43495         }
43496
43497  return_ptr:
43498         return DUK_GET_TVAL_NEGIDX(thr, -1);
43499
43500  fail:
43501         DUK_D(DUK_DPRINT("debug connection error: failed to decode tval"));
43502         DUK__SET_CONN_BROKEN(thr, 1);
43503         return NULL;
43504 }
43505
43506 /*
43507  *  Debug connection write primitives
43508  */
43509
43510 /* Write fully. */
43511 DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) {
43512         duk_heap *heap;
43513         const duk_uint8_t *p;
43514         duk_size_t left;
43515         duk_size_t got;
43516
43517         DUK_ASSERT(thr != NULL);
43518         DUK_ASSERT(length == 0 || data != NULL);
43519         heap = thr->heap;
43520         DUK_ASSERT(heap != NULL);
43521
43522         if (heap->dbg_write_cb == NULL) {
43523                 DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore", (long) length));
43524                 return;
43525         }
43526         if (length == 0) {
43527                 /* Avoid doing an actual write callback with length == 0,
43528                  * because that's reserved for a write flush.
43529                  */
43530                 return;
43531         }
43532         DUK_ASSERT(data != NULL);
43533
43534         p = data;
43535         for (;;) {
43536                 left = (duk_size_t) ((data + length) - p);
43537                 if (left == 0) {
43538                         break;
43539                 }
43540                 DUK_ASSERT(heap->dbg_write_cb != NULL);
43541                 DUK_ASSERT(left >= 1);
43542 #if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
43543                 left = 1;
43544 #endif
43545                 DUK__DBG_TPORT_ENTER();
43546                 got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
43547                 DUK__DBG_TPORT_EXIT();
43548
43549                 if (got == 0 || got > left) {
43550                         duk__debug_null_most_callbacks(thr);  /* avoid calling write callback in detach1() */
43551                         DUK_D(DUK_DPRINT("connection error during write"));
43552                         DUK__SET_CONN_BROKEN(thr, 1);
43553                         return;
43554                 }
43555                 p += got;
43556         }
43557 }
43558
43559 DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
43560         duk_debug_write_bytes(thr, (const duk_uint8_t *) &x, 1);
43561 }
43562
43563 DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
43564         duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
43565 }
43566
43567 DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) {
43568         duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
43569 }
43570
43571 #if defined(DUK_USE_DEBUGGER_INSPECT)
43572 DUK_INTERNAL void duk_debug_write_null(duk_hthread *thr) {
43573         duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
43574 }
43575 #endif
43576
43577 DUK_INTERNAL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val) {
43578         duk_debug_write_byte(thr, val ? DUK_DBG_IB_TRUE : DUK_DBG_IB_FALSE);
43579 }
43580
43581 /* Write signed 32-bit integer. */
43582 DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) {
43583         duk_uint8_t buf[5];
43584         duk_size_t len;
43585
43586         DUK_ASSERT(thr != NULL);
43587
43588         if (x >= 0 && x <= 0x3fL) {
43589                 buf[0] = (duk_uint8_t) (0x80 + x);
43590                 len = 1;
43591         } else if (x >= 0 && x <= 0x3fffL) {
43592                 buf[0] = (duk_uint8_t) (0xc0 + (x >> 8));
43593                 buf[1] = (duk_uint8_t) (x & 0xff);
43594                 len = 2;
43595         } else {
43596                 /* Signed integers always map to 4 bytes now. */
43597                 buf[0] = (duk_uint8_t) DUK_DBG_IB_INT4;
43598                 buf[1] = (duk_uint8_t) ((x >> 24) & 0xff);
43599                 buf[2] = (duk_uint8_t) ((x >> 16) & 0xff);
43600                 buf[3] = (duk_uint8_t) ((x >> 8) & 0xff);
43601                 buf[4] = (duk_uint8_t) (x & 0xff);
43602                 len = 5;
43603         }
43604         duk_debug_write_bytes(thr, buf, len);
43605 }
43606
43607 /* Write unsigned 32-bit integer. */
43608 DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) {
43609         /* The debugger protocol doesn't support a plain integer encoding for
43610          * the full 32-bit unsigned range (only 32-bit signed).  For now,
43611          * unsigned 32-bit values simply written as signed ones.  This is not
43612          * a concrete issue except for 32-bit heaphdr fields.  Proper solutions
43613          * would be to (a) write such integers as IEEE doubles or (b) add an
43614          * unsigned 32-bit dvalue.
43615          */
43616         if (x >= 0x80000000UL) {
43617                 DUK_D(DUK_DPRINT("writing unsigned integer 0x%08lx as signed integer",
43618                                  (long) x));
43619         }
43620         duk_debug_write_int(thr, (duk_int32_t) x);
43621 }
43622
43623 DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) {
43624         duk_uint8_t buf[5];
43625         duk_size_t buflen;
43626
43627         DUK_ASSERT(thr != NULL);
43628         DUK_ASSERT(length == 0 || data != NULL);
43629
43630         if (length <= 0x1fUL && marker_base == DUK_DBG_IB_STR4) {
43631                 /* For strings, special form for short lengths. */
43632                 buf[0] = (duk_uint8_t) (0x60 + length);
43633                 buflen = 1;
43634         } else if (length <= 0xffffUL) {
43635                 buf[0] = (duk_uint8_t) (marker_base + 1);
43636                 buf[1] = (duk_uint8_t) (length >> 8);
43637                 buf[2] = (duk_uint8_t) (length & 0xff);
43638                 buflen = 3;
43639         } else {
43640                 buf[0] = (duk_uint8_t) marker_base;
43641                 buf[1] = (duk_uint8_t) (length >> 24);
43642                 buf[2] = (duk_uint8_t) ((length >> 16) & 0xff);
43643                 buf[3] = (duk_uint8_t) ((length >> 8) & 0xff);
43644                 buf[4] = (duk_uint8_t) (length & 0xff);
43645                 buflen = 5;
43646         }
43647
43648         duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen);
43649         duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length);
43650 }
43651
43652 DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) {
43653         duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_STR4);
43654 }
43655
43656 DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) {
43657         DUK_ASSERT(thr != NULL);
43658
43659         duk_debug_write_string(thr,
43660                                data,
43661                                data ? DUK_STRLEN(data) : 0);
43662 }
43663
43664 DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
43665         DUK_ASSERT(thr != NULL);
43666
43667         /* XXX: differentiate null pointer from empty string? */
43668         duk_debug_write_string(thr,
43669                                (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL),
43670                                (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0));
43671 }
43672
43673 DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) {
43674         duk_debug_write_hstring(thr, duk_safe_to_hstring(thr, -1));
43675 }
43676
43677 DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
43678         duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_BUF4);
43679 }
43680
43681 DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
43682         DUK_ASSERT(thr != NULL);
43683
43684         duk_debug_write_buffer(thr,
43685                                (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL),
43686                                (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0));
43687 }
43688
43689 DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) {
43690         duk_uint8_t buf[2];
43691         duk__ptr_union pu;
43692
43693         DUK_ASSERT(thr != NULL);
43694         DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16);
43695         /* ptr may be NULL */
43696
43697         buf[0] = ibyte;
43698         buf[1] = sizeof(pu);
43699         duk_debug_write_bytes(thr, buf, 2);
43700         pu.p = (void *) ptr;
43701 #if defined(DUK_USE_INTEGER_LE)
43702         duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
43703 #endif
43704         duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
43705 }
43706
43707 DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) {
43708         duk__debug_write_pointer_raw(thr, ptr, DUK_DBG_IB_POINTER);
43709 }
43710
43711 #if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
43712 DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) {
43713         duk__debug_write_pointer_raw(thr, (void *) h, DUK_DBG_IB_HEAPPTR);
43714 }
43715 #endif  /* DUK_USE_DEBUGGER_DUMPHEAP || DUK_USE_DEBUGGER_INSPECT */
43716
43717 DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
43718         duk_uint8_t buf[3];
43719         duk__ptr_union pu;
43720
43721         DUK_ASSERT(thr != NULL);
43722         DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16);
43723         DUK_ASSERT(obj != NULL);
43724
43725         buf[0] = DUK_DBG_IB_OBJECT;
43726         buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj);
43727         buf[2] = sizeof(pu);
43728         duk_debug_write_bytes(thr, buf, 3);
43729         pu.p = (void *) obj;
43730 #if defined(DUK_USE_INTEGER_LE)
43731         duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
43732 #endif
43733         duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
43734 }
43735
43736 DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
43737         duk_c_function lf_func;
43738         duk_small_uint_t lf_flags;
43739         duk_uint8_t buf[4];
43740         duk_double_union du1;
43741         duk_double_union du2;
43742         duk_int32_t i32;
43743
43744         DUK_ASSERT(thr != NULL);
43745         DUK_ASSERT(tv != NULL);
43746
43747         switch (DUK_TVAL_GET_TAG(tv)) {
43748         case DUK_TAG_UNDEFINED:
43749                 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
43750                 break;
43751         case DUK_TAG_UNUSED:
43752                 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
43753                 break;
43754         case DUK_TAG_NULL:
43755                 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
43756                 break;
43757         case DUK_TAG_BOOLEAN:
43758                 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 ||
43759                            DUK_TVAL_GET_BOOLEAN(tv) == 1);
43760                 duk_debug_write_boolean(thr, DUK_TVAL_GET_BOOLEAN(tv));
43761                 break;
43762         case DUK_TAG_POINTER:
43763                 duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv));
43764                 break;
43765         case DUK_TAG_LIGHTFUNC:
43766                 DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags);
43767                 buf[0] = DUK_DBG_IB_LIGHTFUNC;
43768                 buf[1] = (duk_uint8_t) (lf_flags >> 8);
43769                 buf[2] = (duk_uint8_t) (lf_flags & 0xff);
43770                 buf[3] = sizeof(lf_func);
43771                 duk_debug_write_bytes(thr, buf, 4);
43772                 duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func));
43773                 break;
43774         case DUK_TAG_STRING:
43775                 duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv));
43776                 break;
43777         case DUK_TAG_OBJECT:
43778                 duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv));
43779                 break;
43780         case DUK_TAG_BUFFER:
43781                 duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv));
43782                 break;
43783 #if defined(DUK_USE_FASTINT)
43784         case DUK_TAG_FASTINT:
43785 #endif
43786         default:
43787                 /* Numbers are normalized to big (network) endian.  We can
43788                  * (but are not required) to use integer dvalues when there's
43789                  * no loss of precision.
43790                  *
43791                  * XXX: share check with other code; this check is slow but
43792                  * reliable and doesn't require careful exponent/mantissa
43793                  * mask tricks as in the fastint downgrade code.
43794                  */
43795                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
43796                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
43797                 du1.d = DUK_TVAL_GET_NUMBER(tv);
43798                 i32 = (duk_int32_t) du1.d;
43799                 du2.d = (duk_double_t) i32;
43800
43801                 DUK_DD(DUK_DDPRINT("i32=%ld du1=%02x%02x%02x%02x%02x%02x%02x%02x "
43802                                    "du2=%02x%02x%02x%02x%02x%02x%02x%02x",
43803                                    (long) i32,
43804                                    (unsigned int) du1.uc[0], (unsigned int) du1.uc[1],
43805                                    (unsigned int) du1.uc[2], (unsigned int) du1.uc[3],
43806                                    (unsigned int) du1.uc[4], (unsigned int) du1.uc[5],
43807                                    (unsigned int) du1.uc[6], (unsigned int) du1.uc[7],
43808                                    (unsigned int) du2.uc[0], (unsigned int) du2.uc[1],
43809                                    (unsigned int) du2.uc[2], (unsigned int) du2.uc[3],
43810                                    (unsigned int) du2.uc[4], (unsigned int) du2.uc[5],
43811                                    (unsigned int) du2.uc[6], (unsigned int) du2.uc[7]));
43812
43813                 if (duk_memcmp((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) {
43814                         duk_debug_write_int(thr, i32);
43815                 } else {
43816                         DUK_DBLUNION_DOUBLE_HTON(&du1);
43817                         duk_debug_write_byte(thr, DUK_DBG_IB_NUMBER);
43818                         duk_debug_write_bytes(thr, (const duk_uint8_t *) du1.uc, sizeof(du1.uc));
43819                 }
43820         }
43821 }
43822
43823 #if defined(DUK_USE_DEBUGGER_DUMPHEAP)
43824 /* Variant for writing duk_tvals so that any heap allocated values are
43825  * written out as tagged heap pointers.
43826  */
43827 DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) {
43828         if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
43829                 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
43830                 duk_debug_write_heapptr(thr, h);
43831         } else {
43832                 duk_debug_write_tval(thr, tv);
43833         }
43834 }
43835 #endif  /* DUK_USE_DEBUGGER_DUMPHEAP */
43836
43837 /*
43838  *  Debug connection message write helpers
43839  */
43840
43841 #if 0  /* unused */
43842 DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) {
43843         duk_debug_write_byte(thr, DUK_DBG_IB_REQUEST);
43844         duk_debug_write_int(thr, command);
43845 }
43846 #endif
43847
43848 DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) {
43849         duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
43850 }
43851
43852 DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) {
43853         /* Allow NULL 'msg' */
43854         duk_debug_write_byte(thr, DUK_DBG_IB_ERROR);
43855         duk_debug_write_int(thr, (duk_int32_t) err_code);
43856         duk_debug_write_cstring(thr, msg);
43857         duk_debug_write_eom(thr);
43858 }
43859
43860 DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
43861         duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY);
43862         duk_debug_write_int(thr, (duk_int32_t) command);
43863 }
43864
43865 DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
43866         duk_debug_write_byte(thr, DUK_DBG_IB_EOM);
43867
43868         /* As an initial implementation, write flush after every EOM (and the
43869          * version identifier).  A better implementation would flush only when
43870          * Duktape is finished processing messages so that a flush only happens
43871          * after all outbound messages are finished on that occasion.
43872          */
43873         duk_debug_write_flush(thr);
43874 }
43875
43876 /*
43877  *  Status message and helpers
43878  */
43879
43880 DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
43881         duk_activation *act;
43882         duk_uint_fast32_t line;
43883         duk_uint_fast32_t pc;
43884
43885         act = thr->callstack_curr;
43886         if (act == NULL) {
43887                 return 0;
43888         }
43889
43890         /* We're conceptually between two opcodes; act->pc indicates the next
43891          * instruction to be executed.  This is usually the correct pc/line to
43892          * indicate in Status.  (For the 'debugger' statement this now reports
43893          * the pc/line after the debugger statement because the debugger opcode
43894          * has already been executed.)
43895          */
43896
43897         pc = duk_hthread_get_act_curr_pc(thr, act);
43898
43899         /* XXX: this should be optimized to be a raw query and avoid valstack
43900          * operations if possible.
43901          */
43902         duk_push_tval(thr, &act->tv_func);
43903         line = duk_hobject_pc2line_query(thr, -1, pc);
43904         duk_pop(thr);
43905         return line;
43906 }
43907
43908 DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
43909         duk_activation *act;
43910
43911         duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
43912         duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0));
43913
43914         act = thr->callstack_curr;
43915         if (act == NULL) {
43916                 duk_debug_write_undefined(thr);
43917                 duk_debug_write_undefined(thr);
43918                 duk_debug_write_int(thr, 0);
43919                 duk_debug_write_int(thr, 0);
43920         } else {
43921                 duk_push_tval(thr, &act->tv_func);
43922                 duk_get_prop_literal(thr, -1, "fileName");
43923                 duk__debug_write_hstring_safe_top(thr);
43924                 duk_get_prop_literal(thr, -2, "name");
43925                 duk__debug_write_hstring_safe_top(thr);
43926                 duk_pop_3(thr);
43927                 /* Report next pc/line to be executed. */
43928                 duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
43929                 duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
43930         }
43931
43932         duk_debug_write_eom(thr);
43933 }
43934
43935 #if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
43936 DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
43937         /*
43938          *  NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM
43939          */
43940
43941         duk_activation *act;
43942         duk_uint32_t pc;
43943
43944         DUK_ASSERT(thr->valstack_top > thr->valstack);  /* At least: ... [err] */
43945
43946         duk_debug_write_notify(thr, DUK_DBG_CMD_THROW);
43947         duk_debug_write_int(thr, (duk_int32_t) fatal);
43948
43949         /* Report thrown value to client coerced to string */
43950         duk_dup_top(thr);
43951         duk__debug_write_hstring_safe_top(thr);
43952         duk_pop(thr);
43953
43954         if (duk_is_error(thr, -1)) {
43955                 /* Error instance, use augmented error data directly */
43956                 duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
43957                 duk__debug_write_hstring_safe_top(thr);
43958                 duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER);
43959                 duk_debug_write_uint(thr, duk_get_uint(thr, -1));
43960                 duk_pop_2(thr);
43961         } else {
43962                 /* For anything other than an Error instance, we calculate the
43963                  * error location directly from the current activation if one
43964                  * exists.
43965                  */
43966                 act = thr->callstack_curr;
43967                 if (act != NULL) {
43968                         duk_push_tval(thr, &act->tv_func);
43969                         duk_get_prop_literal(thr, -1, "fileName");
43970                         duk__debug_write_hstring_safe_top(thr);
43971                         pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr, act);
43972                         duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(thr, -2, pc));
43973                         duk_pop_2(thr);
43974                 } else {
43975                         /* Can happen if duk_throw() is called on an empty
43976                          * callstack.
43977                          */
43978                         duk_debug_write_cstring(thr, "");
43979                         duk_debug_write_uint(thr, 0);
43980                 }
43981         }
43982
43983         duk_debug_write_eom(thr);
43984 }
43985 #endif  /* DUK_USE_DEBUGGER_THROW_NOTIFY */
43986
43987 /*
43988  *  Debug message processing
43989  */
43990
43991 /* Skip dvalue. */
43992 DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
43993         duk_uint8_t x;
43994         duk_uint32_t len;
43995
43996         x = duk_debug_read_byte(thr);
43997
43998         if (x >= 0xc0) {
43999                 duk_debug_skip_byte(thr);
44000                 return 0;
44001         }
44002         if (x >= 0x80) {
44003                 return 0;
44004         }
44005         if (x >= 0x60) {
44006                 duk_debug_skip_bytes(thr, (duk_size_t) (x - 0x60));
44007                 return 0;
44008         }
44009         switch(x) {
44010         case DUK_DBG_IB_EOM:
44011                 return 1;  /* Return 1: got EOM */
44012         case DUK_DBG_IB_REQUEST:
44013         case DUK_DBG_IB_REPLY:
44014         case DUK_DBG_IB_ERROR:
44015         case DUK_DBG_IB_NOTIFY:
44016                 break;
44017         case DUK_DBG_IB_INT4:
44018                 (void) duk__debug_read_uint32_raw(thr);
44019                 break;
44020         case DUK_DBG_IB_STR4:
44021         case DUK_DBG_IB_BUF4:
44022                 len = duk__debug_read_uint32_raw(thr);
44023                 duk_debug_skip_bytes(thr, len);
44024                 break;
44025         case DUK_DBG_IB_STR2:
44026         case DUK_DBG_IB_BUF2:
44027                 len = duk__debug_read_uint16_raw(thr);
44028                 duk_debug_skip_bytes(thr, len);
44029                 break;
44030         case DUK_DBG_IB_UNUSED:
44031         case DUK_DBG_IB_UNDEFINED:
44032         case DUK_DBG_IB_NULL:
44033         case DUK_DBG_IB_TRUE:
44034         case DUK_DBG_IB_FALSE:
44035                 break;
44036         case DUK_DBG_IB_NUMBER:
44037                 duk_debug_skip_bytes(thr, 8);
44038                 break;
44039         case DUK_DBG_IB_OBJECT:
44040                 duk_debug_skip_byte(thr);
44041                 len = duk_debug_read_byte(thr);
44042                 duk_debug_skip_bytes(thr, len);
44043                 break;
44044         case DUK_DBG_IB_POINTER:
44045         case DUK_DBG_IB_HEAPPTR:
44046                 len = duk_debug_read_byte(thr);
44047                 duk_debug_skip_bytes(thr, len);
44048                 break;
44049         case DUK_DBG_IB_LIGHTFUNC:
44050                 duk_debug_skip_bytes(thr, 2);
44051                 len = duk_debug_read_byte(thr);
44052                 duk_debug_skip_bytes(thr, len);
44053                 break;
44054         default:
44055                 goto fail;
44056         }
44057
44058         return 0;
44059
44060  fail:
44061         DUK__SET_CONN_BROKEN(thr, 1);
44062         return 1;  /* Pretend like we got EOM */
44063 }
44064
44065 /* Skip dvalues to EOM. */
44066 DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
44067         for (;;) {
44068                 if (duk__debug_skip_dvalue(thr)) {
44069                         break;
44070                 }
44071         }
44072 }
44073
44074 /* Read and validate a call stack index.  If index is invalid, write out an
44075  * error message and return zero.
44076  */
44077 DUK_LOCAL duk_int32_t duk__debug_read_validate_csindex(duk_hthread *thr) {
44078         duk_int32_t level;
44079         level = duk_debug_read_int(thr);
44080         if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
44081                 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
44082                 return 0;  /* zero indicates failure */
44083         }
44084         return level;
44085 }
44086
44087 /* Read a call stack index and lookup the corresponding duk_activation.
44088  * If index is invalid, write out an error message and return NULL.
44089  */
44090 DUK_LOCAL duk_activation *duk__debug_read_level_get_activation(duk_hthread *thr) {
44091         duk_activation *act;
44092         duk_int32_t level;
44093
44094         level = duk_debug_read_int(thr);
44095         act = duk_hthread_get_activation_for_level(thr, level);
44096         if (act == NULL) {
44097                 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
44098         }
44099         return act;
44100 }
44101
44102 /*
44103  *  Simple commands
44104  */
44105
44106 DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) {
44107         DUK_UNREF(heap);
44108         DUK_D(DUK_DPRINT("debug command Version"));
44109
44110         duk_debug_write_reply(thr);
44111         duk_debug_write_int(thr, DUK_VERSION);
44112         duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE);
44113         duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO);
44114 #if defined(DUK_USE_DOUBLE_LE)
44115         duk_debug_write_int(thr, 1);
44116 #elif defined(DUK_USE_DOUBLE_ME)
44117         duk_debug_write_int(thr, 2);
44118 #elif defined(DUK_USE_DOUBLE_BE)
44119         duk_debug_write_int(thr, 3);
44120 #else
44121         duk_debug_write_int(thr, 0);
44122 #endif
44123         duk_debug_write_int(thr, (duk_int_t) sizeof(void *));
44124         duk_debug_write_eom(thr);
44125 }
44126
44127 DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) {
44128         DUK_UNREF(heap);
44129         DUK_D(DUK_DPRINT("debug command TriggerStatus"));
44130
44131         duk_debug_write_reply(thr);
44132         duk_debug_write_eom(thr);
44133         heap->dbg_state_dirty = 1;
44134 }
44135
44136 DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
44137         DUK_D(DUK_DPRINT("debug command Pause"));
44138         duk_debug_set_paused(heap);
44139         duk_debug_write_reply(thr);
44140         duk_debug_write_eom(thr);
44141 }
44142
44143 DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
44144         duk_small_uint_t pause_flags;
44145
44146         DUK_D(DUK_DPRINT("debug command Resume"));
44147
44148         duk_debug_clear_paused(heap);
44149
44150         pause_flags = 0;
44151 #if 0  /* manual testing */
44152         pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE;
44153         pause_flags |= DUK_PAUSE_FLAG_CAUGHT_ERROR;
44154         pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
44155 #endif
44156 #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
44157         pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
44158 #endif
44159
44160         duk__debug_set_pause_state(thr, heap, pause_flags);
44161
44162         duk_debug_write_reply(thr);
44163         duk_debug_write_eom(thr);
44164 }
44165
44166 DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
44167         duk_small_uint_t pause_flags;
44168
44169         DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd));
44170
44171         if (cmd == DUK_DBG_CMD_STEPINTO) {
44172                 pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE |
44173                               DUK_PAUSE_FLAG_FUNC_ENTRY |
44174                               DUK_PAUSE_FLAG_FUNC_EXIT;
44175         } else if (cmd == DUK_DBG_CMD_STEPOVER) {
44176                 pause_flags = DUK_PAUSE_FLAG_LINE_CHANGE |
44177                               DUK_PAUSE_FLAG_FUNC_EXIT;
44178         } else {
44179                 DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
44180                 pause_flags = DUK_PAUSE_FLAG_FUNC_EXIT;
44181         }
44182 #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
44183         pause_flags |= DUK_PAUSE_FLAG_UNCAUGHT_ERROR;
44184 #endif
44185
44186         /* If current activation doesn't have line information, line-based
44187          * pause flags are automatically disabled.  As a result, e.g.
44188          * StepInto will then pause on (native) function entry or exit.
44189          */
44190         duk_debug_clear_paused(heap);
44191         duk__debug_set_pause_state(thr, heap, pause_flags);
44192
44193         duk_debug_write_reply(thr);
44194         duk_debug_write_eom(thr);
44195 }
44196
44197 DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) {
44198         duk_small_int_t i;
44199
44200         DUK_D(DUK_DPRINT("debug command ListBreak"));
44201         duk_debug_write_reply(thr);
44202         for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) {
44203                 duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename);
44204                 duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line);
44205         }
44206         duk_debug_write_eom(thr);
44207 }
44208
44209 DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
44210         duk_hstring *filename;
44211         duk_uint32_t linenumber;
44212         duk_small_int_t idx;
44213
44214         DUK_UNREF(heap);
44215
44216         filename = duk_debug_read_hstring(thr);
44217         linenumber = (duk_uint32_t) duk_debug_read_int(thr);
44218         DUK_D(DUK_DPRINT("debug command AddBreak: %!O:%ld", (duk_hobject *) filename, (long) linenumber));
44219         idx = duk_debug_add_breakpoint(thr, filename, linenumber);
44220         if (idx >= 0) {
44221                 duk_debug_write_reply(thr);
44222                 duk_debug_write_int(thr, (duk_int32_t) idx);
44223                 duk_debug_write_eom(thr);
44224         } else {
44225                 duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint");
44226         }
44227 }
44228
44229 DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
44230         duk_small_uint_t idx;
44231
44232         DUK_UNREF(heap);
44233
44234         DUK_D(DUK_DPRINT("debug command DelBreak"));
44235         idx = (duk_small_uint_t) duk_debug_read_int(thr);
44236         if (duk_debug_remove_breakpoint(thr, idx)) {
44237                 duk_debug_write_reply(thr);
44238                 duk_debug_write_eom(thr);
44239         } else {
44240                 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index");
44241         }
44242 }
44243
44244 DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
44245         duk_activation *act;
44246         duk_hstring *str;
44247         duk_bool_t rc;
44248
44249         DUK_UNREF(heap);
44250         DUK_D(DUK_DPRINT("debug command GetVar"));
44251
44252         act = duk__debug_read_level_get_activation(thr);
44253         if (act == NULL) {
44254                 return;
44255         }
44256         str = duk_debug_read_hstring(thr);  /* push to stack */
44257         DUK_ASSERT(str != NULL);
44258
44259         rc = duk_js_getvar_activation(thr, act, str, 0);
44260
44261         duk_debug_write_reply(thr);
44262         if (rc) {
44263                 duk_debug_write_int(thr, 1);
44264                 DUK_ASSERT(duk_get_tval(thr, -2) != NULL);
44265                 duk_debug_write_tval(thr, duk_get_tval(thr, -2));
44266         } else {
44267                 duk_debug_write_int(thr, 0);
44268                 duk_debug_write_unused(thr);
44269         }
44270         duk_debug_write_eom(thr);
44271 }
44272
44273 DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
44274         duk_activation *act;
44275         duk_hstring *str;
44276         duk_tval *tv;
44277
44278         DUK_UNREF(heap);
44279         DUK_D(DUK_DPRINT("debug command PutVar"));
44280
44281         act = duk__debug_read_level_get_activation(thr);
44282         if (act == NULL) {
44283                 return;
44284         }
44285         str = duk_debug_read_hstring(thr);  /* push to stack */
44286         DUK_ASSERT(str != NULL);
44287         tv = duk_debug_read_tval(thr);
44288         if (tv == NULL) {
44289                 /* detached */
44290                 return;
44291         }
44292
44293         duk_js_putvar_activation(thr, act, str, tv, 0);
44294
44295         /* XXX: Current putvar implementation doesn't have a success flag,
44296          * add one and send to debug client?
44297          */
44298         duk_debug_write_reply(thr);
44299         duk_debug_write_eom(thr);
44300 }
44301
44302 DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
44303         duk_hthread *curr_thr = thr;
44304         duk_activation *curr_act;
44305         duk_uint_fast32_t pc;
44306         duk_uint_fast32_t line;
44307
44308         DUK_ASSERT(thr != NULL);
44309         DUK_UNREF(heap);
44310
44311         duk_debug_write_reply(thr);
44312         while (curr_thr != NULL) {
44313                 for (curr_act = curr_thr->callstack_curr; curr_act != NULL; curr_act = curr_act->parent) {
44314                         /* PC/line semantics here are:
44315                          *   - For callstack top we're conceptually between two
44316                          *     opcodes and current PC indicates next line to
44317                          *     execute, so report that (matches Status).
44318                          *   - For other activations we're conceptually still
44319                          *     executing the instruction at PC-1, so report that
44320                          *     (matches error stacktrace behavior).
44321                          *   - See: https://github.com/svaarala/duktape/issues/281
44322                          */
44323
44324                         /* XXX: optimize to use direct reads, i.e. avoid
44325                          * value stack operations.
44326                          */
44327                         duk_push_tval(thr, &curr_act->tv_func);
44328                         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
44329                         duk__debug_write_hstring_safe_top(thr);
44330                         duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
44331                         duk__debug_write_hstring_safe_top(thr);
44332                         pc = duk_hthread_get_act_curr_pc(thr, curr_act);
44333                         if (curr_act != curr_thr->callstack_curr && pc > 0) {
44334                                 pc--;
44335                         }
44336                         line = duk_hobject_pc2line_query(thr, -3, pc);
44337                         duk_debug_write_uint(thr, (duk_uint32_t) line);
44338                         duk_debug_write_uint(thr, (duk_uint32_t) pc);
44339                         duk_pop_3(thr);
44340                 }
44341                 curr_thr = curr_thr->resumer;
44342         }
44343         /* SCANBUILD: warning about 'thr' potentially being NULL here,
44344          * warning is incorrect because thr != NULL always here.
44345          */
44346         duk_debug_write_eom(thr);
44347 }
44348
44349 DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
44350         duk_activation *act;
44351         duk_hstring *varname;
44352
44353         DUK_UNREF(heap);
44354
44355         act = duk__debug_read_level_get_activation(thr);
44356         if (act == NULL) {
44357                 return;
44358         }
44359
44360         duk_debug_write_reply(thr);
44361
44362         /* XXX: several nice-to-have improvements here:
44363          *   - Use direct reads avoiding value stack operations
44364          *   - Avoid triggering getters, indicate getter values to debug client
44365          *   - If side effects are possible, add error catching
44366          */
44367
44368         duk_push_tval(thr, &act->tv_func);
44369         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_VARMAP);
44370         if (duk_is_object(thr, -1)) {
44371                 duk_enum(thr, -1, 0 /*enum_flags*/);
44372                 while (duk_next(thr, -1 /*enum_index*/, 0 /*get_value*/)) {
44373                         varname = duk_known_hstring(thr, -1);
44374
44375                         duk_js_getvar_activation(thr, act, varname, 0 /*throw_flag*/);
44376                         /* [ ... func varmap enum key value this ] */
44377                         duk_debug_write_hstring(thr, duk_get_hstring(thr, -3));
44378                         duk_debug_write_tval(thr, duk_get_tval(thr, -2));
44379                         duk_pop_3(thr);  /* -> [ ... func varmap enum ] */
44380                 }
44381         } else {
44382                 DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
44383         }
44384
44385         duk_debug_write_eom(thr);
44386 }
44387
44388 DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
44389         duk_small_uint_t call_flags;
44390         duk_int_t call_ret;
44391         duk_small_int_t eval_err;
44392         duk_bool_t direct_eval;
44393         duk_int32_t level;
44394         duk_idx_t idx_func;
44395
44396         DUK_UNREF(heap);
44397
44398         DUK_D(DUK_DPRINT("debug command Eval"));
44399
44400         /* The eval code is executed within the lexical environment of a specified
44401          * activation.  For now, use global object eval() function, with the eval
44402          * considered a 'direct call to eval'.
44403          *
44404          * Callstack index for debug commands only affects scope -- the callstack
44405          * as seen by, e.g. Duktape.act() will be the same regardless.
44406          */
44407
44408         /* nargs == 2 so we can pass a callstack index to eval(). */
44409         idx_func = duk_get_top(thr);
44410         duk_push_c_function(thr, duk_bi_global_object_eval, 2 /*nargs*/);
44411         duk_push_undefined(thr);  /* 'this' binding shouldn't matter here */
44412
44413         /* Read callstack index, if non-null. */
44414         if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) {
44415                 direct_eval = 0;
44416                 level = -1;  /* Not needed, but silences warning. */
44417                 (void) duk_debug_read_byte(thr);
44418         } else {
44419                 direct_eval = 1;
44420                 level = duk__debug_read_validate_csindex(thr);
44421                 if (level == 0) {
44422                         return;
44423                 }
44424         }
44425
44426         DUK_ASSERT(!direct_eval ||
44427                    (level < 0 && -level <= (duk_int32_t) thr->callstack_top));
44428
44429         (void) duk_debug_read_hstring(thr);
44430         if (direct_eval) {
44431                 duk_push_int(thr, level - 1);  /* compensate for eval() call */
44432         }
44433
44434         /* [ ... eval "eval" eval_input level? ] */
44435
44436         call_flags = 0;
44437         if (direct_eval) {
44438                 duk_activation *act;
44439                 duk_hobject *fun;
44440
44441                 act = duk_hthread_get_activation_for_level(thr, level);
44442                 if (act != NULL) {
44443                         fun = DUK_ACT_GET_FUNC(act);
44444                         if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(fun)) {
44445                                 /* Direct eval requires that there's a current
44446                                  * activation and it is an ECMAScript function.
44447                                  * When Eval is executed from e.g. cooperate API
44448                                  * call we'll need to do an indirect eval instead.
44449                                  */
44450                                 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
44451                         }
44452                 }
44453         }
44454
44455         call_ret = duk_pcall_method_flags(thr, duk_get_top(thr) - (idx_func + 2), call_flags);
44456
44457         if (call_ret == DUK_EXEC_SUCCESS) {
44458                 eval_err = 0;
44459                 /* Use result value as is. */
44460         } else {
44461                 /* For errors a string coerced result is most informative
44462                  * right now, as the debug client doesn't have the capability
44463                  * to traverse the error object.
44464                  */
44465                 eval_err = 1;
44466                 duk_safe_to_string(thr, -1);
44467         }
44468
44469         /* [ ... result ] */
44470
44471         duk_debug_write_reply(thr);
44472         duk_debug_write_int(thr, (duk_int32_t) eval_err);
44473         DUK_ASSERT(duk_get_tval(thr, -1) != NULL);
44474         duk_debug_write_tval(thr, duk_get_tval(thr, -1));
44475         duk_debug_write_eom(thr);
44476 }
44477
44478 DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
44479         DUK_UNREF(heap);
44480         DUK_D(DUK_DPRINT("debug command Detach"));
44481
44482         duk_debug_write_reply(thr);
44483         duk_debug_write_eom(thr);
44484
44485         DUK_D(DUK_DPRINT("debug connection detached, mark broken"));
44486         DUK__SET_CONN_BROKEN(thr, 0);  /* not an error */
44487 }
44488
44489 DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
44490         duk_idx_t old_top;
44491
44492         DUK_D(DUK_DPRINT("debug command AppRequest"));
44493
44494         old_top = duk_get_top(thr);  /* save stack top */
44495
44496         if (heap->dbg_request_cb != NULL) {
44497                 duk_idx_t nrets;
44498                 duk_idx_t nvalues = 0;
44499                 duk_idx_t top, idx;
44500
44501                 /* Read tvals from the message and push them onto the valstack,
44502                  * then call the request callback to process the request.
44503                  */
44504                 while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
44505                         duk_tval *tv;
44506                         if (!duk_check_stack(thr, 1)) {
44507                                 DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)"));
44508                                 goto fail;
44509                         }
44510                         tv = duk_debug_read_tval(thr);  /* push to stack */
44511                         if (tv == NULL) {
44512                                 /* detached */
44513                                 return;
44514                         }
44515                         nvalues++;
44516                 }
44517                 DUK_ASSERT(duk_get_top(thr) == old_top + nvalues);
44518
44519                 /* Request callback should push values for reply to client onto valstack */
44520                 DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld",
44521                                  (long) nvalues, (long) old_top, (long) duk_get_top(thr)));
44522                 nrets = heap->dbg_request_cb(thr, heap->dbg_udata, nvalues);
44523                 DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld",
44524                                  (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(thr)));
44525                 if (nrets >= 0) {
44526                         DUK_ASSERT(duk_get_top(thr) >= old_top + nrets);
44527                         if (duk_get_top(thr) < old_top + nrets) {
44528                                 DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, "
44529                                                  "top=%ld < old_top=%ld + nrets=%ld; "
44530                                                  "this might mean it's unsafe to continue!",
44531                                                  (long) duk_get_top(thr), (long) old_top, (long) nrets));
44532                                 goto fail;
44533                         }
44534
44535                         /* Reply with tvals pushed by request callback */
44536                         duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
44537                         top = duk_get_top(thr);
44538                         for (idx = top - nrets; idx < top; idx++) {
44539                                 duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(thr, idx));
44540                         }
44541                         duk_debug_write_eom(thr);
44542                 } else {
44543                         DUK_ASSERT(duk_get_top(thr) >= old_top + 1);
44544                         if (duk_get_top(thr) < old_top + 1) {
44545                                 DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration"));
44546                                 goto fail;
44547                         }
44548                         duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(thr, -1));
44549                 }
44550
44551                 duk_set_top(thr, old_top);  /* restore stack top */
44552         } else {
44553                 DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported"));
44554                 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target");
44555         }
44556
44557         return;
44558
44559  fail:
44560         duk_set_top(thr, old_top);  /* restore stack top */
44561         DUK__SET_CONN_BROKEN(thr, 1);
44562 }
44563
44564 /*
44565  *  DumpHeap command
44566  */
44567
44568 #if defined(DUK_USE_DEBUGGER_DUMPHEAP)
44569 /* XXX: this has some overlap with object inspection; remove this and make
44570  * DumpHeap return lists of heapptrs instead?
44571  */
44572 DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) {
44573         DUK_UNREF(heap);
44574
44575         duk_debug_write_heapptr(thr, hdr);
44576         duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr));
44577         duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr));
44578 #if defined(DUK_USE_REFERENCE_COUNTING)
44579         duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr));
44580 #else
44581         duk_debug_write_int(thr, (duk_int32_t) -1);
44582 #endif
44583
44584         switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
44585         case DUK_HTYPE_STRING: {
44586                 duk_hstring *h = (duk_hstring *) hdr;
44587
44588                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_BYTELEN(h));
44589                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_CHARLEN(h));
44590                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
44591                 duk_debug_write_hstring(thr, h);
44592                 break;
44593         }
44594         case DUK_HTYPE_OBJECT: {
44595                 duk_hobject *h = (duk_hobject *) hdr;
44596                 duk_hstring *k;
44597                 duk_uint_fast32_t i;
44598
44599                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h));
44600                 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
44601                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h));
44602                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h));
44603                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h));
44604                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h));
44605
44606                 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
44607                         duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i));
44608                         k = DUK_HOBJECT_E_GET_KEY(heap, h, i);
44609                         duk_debug_write_heapptr(thr, (duk_heaphdr *) k);
44610                         if (k == NULL) {
44611                                 duk_debug_write_int(thr, 0);  /* isAccessor */
44612                                 duk_debug_write_unused(thr);
44613                                 continue;
44614                         }
44615                         if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
44616                                 duk_debug_write_int(thr, 1);  /* isAccessor */
44617                                 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
44618                                 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
44619                         } else {
44620                                 duk_debug_write_int(thr, 0);  /* isAccessor */
44621
44622                                 duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
44623                         }
44624                 }
44625
44626                 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
44627                         /* Note: array dump will include elements beyond
44628                          * 'length'.
44629                          */
44630                         duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
44631                 }
44632                 break;
44633         }
44634         case DUK_HTYPE_BUFFER: {
44635                 duk_hbuffer *h = (duk_hbuffer *) hdr;
44636
44637                 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h));
44638                 duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
44639                 break;
44640         }
44641         default: {
44642                 DUK_D(DUK_DPRINT("invalid htype: %d", (int) DUK_HEAPHDR_GET_TYPE(hdr)));
44643         }
44644         }
44645 }
44646
44647 DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) {
44648         duk_heaphdr *hdr;
44649
44650         hdr = heap->heap_allocated;
44651         while (hdr != NULL) {
44652                 duk__debug_dump_heaphdr(thr, heap, hdr);
44653                 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
44654         }
44655 }
44656
44657 DUK_LOCAL void duk__debug_dump_strtab(duk_hthread *thr, duk_heap *heap) {
44658         duk_uint32_t i;
44659         duk_hstring *h;
44660
44661         for (i = 0; i < heap->st_size; i++) {
44662 #if defined(DUK_USE_STRTAB_PTRCOMP)
44663                 h = DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, heap->strtable16[i]);
44664 #else
44665                 h = heap->strtable[i];
44666 #endif
44667                 while (h != NULL) {
44668                         duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
44669                         h = h->hdr.h_next;
44670                 }
44671         }
44672 }
44673
44674 DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) {
44675         DUK_D(DUK_DPRINT("debug command DumpHeap"));
44676
44677         duk_debug_write_reply(thr);
44678         duk__debug_dump_heap_allocated(thr, heap);
44679         duk__debug_dump_strtab(thr, heap);
44680         duk_debug_write_eom(thr);
44681 }
44682 #endif  /* DUK_USE_DEBUGGER_DUMPHEAP */
44683
44684 DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) {
44685         duk_activation *act;
44686         duk_hcompfunc *fun = NULL;
44687         duk_size_t i, n;
44688         duk_tval *tv;
44689         duk_hobject **fn;
44690         duk_int32_t level = -1;
44691         duk_uint8_t ibyte;
44692
44693         DUK_UNREF(heap);
44694
44695         DUK_D(DUK_DPRINT("debug command GetBytecode"));
44696
44697         ibyte = duk_debug_peek_byte(thr);
44698         if (ibyte != DUK_DBG_IB_EOM) {
44699                 tv = duk_debug_read_tval(thr);
44700                 if (tv == NULL) {
44701                         /* detached */
44702                         return;
44703                 }
44704                 if (DUK_TVAL_IS_OBJECT(tv)) {
44705                         /* tentative, checked later */
44706                         fun = (duk_hcompfunc *) DUK_TVAL_GET_OBJECT(tv);
44707                         DUK_ASSERT(fun != NULL);
44708                 } else if (DUK_TVAL_IS_NUMBER(tv)) {
44709                         level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv);
44710                 } else {
44711                         DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!T", tv));
44712                         goto fail_args;
44713                 }
44714         }
44715
44716         if (fun == NULL) {
44717                 act = duk_hthread_get_activation_for_level(thr, level);
44718                 if (act == NULL) {
44719                         goto fail_index;
44720                 }
44721                 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
44722         }
44723
44724         if (fun == NULL || !DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)) {
44725                 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O", fun));
44726                 goto fail_args;
44727         }
44728         DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun));
44729
44730         duk_debug_write_reply(thr);
44731         n = DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap, fun);
44732         duk_debug_write_int(thr, (duk_int32_t) n);
44733         tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, fun);
44734         for (i = 0; i < n; i++) {
44735                 duk_debug_write_tval(thr, tv);
44736                 tv++;
44737         }
44738         n = DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap, fun);
44739         duk_debug_write_int(thr, (duk_int32_t) n);
44740         fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, fun);
44741         for (i = 0; i < n; i++) {
44742                 duk_debug_write_hobject(thr, *fn);
44743                 fn++;
44744         }
44745         duk_debug_write_string(thr,
44746                                (const char *) DUK_HCOMPFUNC_GET_CODE_BASE(heap, fun),
44747                                (duk_size_t) DUK_HCOMPFUNC_GET_CODE_SIZE(heap, fun));
44748         duk_debug_write_eom(thr);
44749         return;
44750
44751  fail_args:
44752         duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument");
44753         return;
44754
44755  fail_index:
44756         duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
44757         return;
44758 }
44759
44760 /*
44761  *  Object inspection commands: GetHeapObjInfo, GetObjPropDesc,
44762  *  GetObjPropDescRange
44763  */
44764
44765 #if defined(DUK_USE_DEBUGGER_INSPECT)
44766
44767 #if 0 /* pruned */
44768 DUK_LOCAL const char * const duk__debug_getinfo_heaphdr_keys[] = {
44769         "reachable",
44770         "temproot",
44771         "finalizable",
44772         "finalized",
44773         "readonly"
44774         /* NULL not needed here */
44775 };
44776 DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = {
44777         DUK_HEAPHDR_FLAG_REACHABLE,
44778         DUK_HEAPHDR_FLAG_TEMPROOT,
44779         DUK_HEAPHDR_FLAG_FINALIZABLE,
44780         DUK_HEAPHDR_FLAG_FINALIZED,
44781         DUK_HEAPHDR_FLAG_READONLY,
44782         0  /* terminator */
44783 };
44784 #endif
44785 DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = {
44786 #if 0
44787         "arridx",
44788         "symbol",
44789         "hidden",
44790         "reserved_word",
44791         "strict_reserved_word",
44792         "eval_or_arguments",
44793 #endif
44794         "extdata"
44795         /* NULL not needed here */
44796 };
44797 DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
44798 #if 0
44799         DUK_HSTRING_FLAG_ARRIDX,
44800         DUK_HSTRING_FLAG_SYMBOL,
44801         DUK_HSTRING_FLAG_HIDDEN,
44802         DUK_HSTRING_FLAG_RESERVED_WORD,
44803         DUK_HSTRING_FLAG_STRICT_RESERVED_WORD,
44804         DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS,
44805 #endif
44806         DUK_HSTRING_FLAG_EXTDATA,
44807         0  /* terminator */
44808 };
44809 DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
44810         "extensible",
44811         "constructable",
44812         "callable",
44813         "boundfunc",
44814         "compfunc",
44815         "natfunc",
44816         "bufobj",
44817         "fastrefs",
44818         "array_part",
44819         "strict",
44820         "notail",
44821         "newenv",
44822         "namebinding",
44823         "createargs",
44824         "have_finalizer",
44825         "exotic_array",
44826         "exotic_stringobj",
44827         "exotic_arguments",
44828         "exotic_proxyobj",
44829         "special_call"
44830         /* NULL not needed here */
44831 };
44832 DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
44833         DUK_HOBJECT_FLAG_EXTENSIBLE,
44834         DUK_HOBJECT_FLAG_CONSTRUCTABLE,
44835         DUK_HOBJECT_FLAG_CALLABLE,
44836         DUK_HOBJECT_FLAG_BOUNDFUNC,
44837         DUK_HOBJECT_FLAG_COMPFUNC,
44838         DUK_HOBJECT_FLAG_NATFUNC,
44839         DUK_HOBJECT_FLAG_BUFOBJ,
44840         DUK_HOBJECT_FLAG_FASTREFS,
44841         DUK_HOBJECT_FLAG_ARRAY_PART,
44842         DUK_HOBJECT_FLAG_STRICT,
44843         DUK_HOBJECT_FLAG_NOTAIL,
44844         DUK_HOBJECT_FLAG_NEWENV,
44845         DUK_HOBJECT_FLAG_NAMEBINDING,
44846         DUK_HOBJECT_FLAG_CREATEARGS,
44847         DUK_HOBJECT_FLAG_HAVE_FINALIZER,
44848         DUK_HOBJECT_FLAG_EXOTIC_ARRAY,
44849         DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ,
44850         DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS,
44851         DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ,
44852         DUK_HOBJECT_FLAG_SPECIAL_CALL,
44853         0  /* terminator */
44854 };
44855 DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = {
44856         "dynamic",
44857         "external"
44858         /* NULL not needed here */
44859 };
44860 DUK_LOCAL duk_uint_t duk__debug_getinfo_hbuffer_masks[] = {
44861         DUK_HBUFFER_FLAG_DYNAMIC,
44862         DUK_HBUFFER_FLAG_EXTERNAL,
44863         0  /* terminator */
44864 };
44865
44866 DUK_LOCAL void duk__debug_getinfo_flags_key(duk_hthread *thr, const char *key) {
44867         duk_debug_write_uint(thr, 0);
44868         duk_debug_write_cstring(thr, key);
44869 }
44870
44871 DUK_LOCAL void duk__debug_getinfo_prop_uint(duk_hthread *thr, const char *key, duk_uint_t val) {
44872         duk_debug_write_uint(thr, 0);
44873         duk_debug_write_cstring(thr, key);
44874         duk_debug_write_uint(thr, val);
44875 }
44876
44877 DUK_LOCAL void duk__debug_getinfo_prop_int(duk_hthread *thr, const char *key, duk_int_t val) {
44878         duk_debug_write_uint(thr, 0);
44879         duk_debug_write_cstring(thr, key);
44880         duk_debug_write_int(thr, val);
44881 }
44882
44883 DUK_LOCAL void duk__debug_getinfo_prop_bool(duk_hthread *thr, const char *key, duk_bool_t val) {
44884         duk_debug_write_uint(thr, 0);
44885         duk_debug_write_cstring(thr, key);
44886         duk_debug_write_boolean(thr, val);
44887 }
44888
44889 DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const * keys, duk_uint_t *masks, duk_uint_t flags) {
44890         const char *key;
44891         duk_uint_t mask;
44892
44893         for (;;) {
44894                 mask = *masks++;
44895                 if (mask == 0) {
44896                         break;
44897                 }
44898                 key = *keys++;
44899                 DUK_ASSERT(key != NULL);
44900
44901                 DUK_DD(DUK_DDPRINT("inspect bitmask: key=%s, mask=0x%08lx, flags=0x%08lx", key, (unsigned long) mask, (unsigned long) flags));
44902                 duk__debug_getinfo_prop_bool(thr, key, flags & mask);
44903         }
44904 }
44905
44906 /* Inspect a property using a virtual index into a conceptual property list
44907  * consisting of (1) all array part items from [0,a_size[ (even when above
44908  * .length) and (2) all entry part items from [0,e_next[.  Unused slots are
44909  * indicated using dvalue 'unused'.
44910  */
44911 DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap, duk_hobject *h_obj, duk_uint_t idx) {
44912         duk_uint_t a_size;
44913         duk_tval *tv;
44914         duk_hstring *h_key;
44915         duk_hobject *h_getset;
44916         duk_uint_t flags;
44917
44918         DUK_UNREF(heap);
44919
44920         a_size = DUK_HOBJECT_GET_ASIZE(h_obj);
44921         if (idx < a_size) {
44922                 duk_debug_write_uint(thr, DUK_PROPDESC_FLAGS_WEC);
44923                 duk_debug_write_uint(thr, idx);
44924                 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, h_obj, idx);
44925                 duk_debug_write_tval(thr, tv);
44926                 return 1;
44927         }
44928
44929         idx -= a_size;
44930         if (idx >= DUK_HOBJECT_GET_ENEXT(h_obj)) {
44931                 return 0;
44932         }
44933
44934         h_key = DUK_HOBJECT_E_GET_KEY(heap, h_obj, idx);
44935         if (h_key == NULL) {
44936                 duk_debug_write_uint(thr, 0);
44937                 duk_debug_write_null(thr);
44938                 duk_debug_write_unused(thr);
44939                 return 1;
44940         }
44941
44942         flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx);
44943         if (DUK_HSTRING_HAS_SYMBOL(h_key)) {
44944                 flags |= DUK_DBG_PROPFLAG_SYMBOL;
44945         }
44946         if (DUK_HSTRING_HAS_HIDDEN(h_key)) {
44947                 flags |= DUK_DBG_PROPFLAG_HIDDEN;
44948         }
44949         duk_debug_write_uint(thr, flags);
44950         duk_debug_write_hstring(thr, h_key);
44951         if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
44952                 h_getset = DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h_obj, idx);
44953                 if (h_getset) {
44954                         duk_debug_write_hobject(thr, h_getset);
44955                 } else {
44956                         duk_debug_write_null(thr);
44957                 }
44958                 h_getset = DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h_obj, idx);
44959                 if (h_getset) {
44960                         duk_debug_write_hobject(thr, h_getset);
44961                 } else {
44962                         duk_debug_write_null(thr);
44963                 }
44964         } else {
44965                 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h_obj, idx);
44966                 duk_debug_write_tval(thr, tv);
44967         }
44968         return 1;
44969 }
44970
44971 DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *heap) {
44972         duk_heaphdr *h;
44973
44974         DUK_D(DUK_DPRINT("debug command GetHeapObjInfo"));
44975         DUK_UNREF(heap);
44976
44977         DUK_ASSERT(sizeof(duk__debug_getinfo_hstring_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hstring_masks) / sizeof(duk_uint_t) - 1);
44978         DUK_ASSERT(sizeof(duk__debug_getinfo_hobject_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hobject_masks) / sizeof(duk_uint_t) - 1);
44979         DUK_ASSERT(sizeof(duk__debug_getinfo_hbuffer_keys) / sizeof(const char *) == sizeof(duk__debug_getinfo_hbuffer_masks) / sizeof(duk_uint_t) - 1);
44980
44981         h = duk_debug_read_any_ptr(thr);
44982         if (!h) {
44983                 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
44984                 return;
44985         }
44986
44987         duk_debug_write_reply(thr);
44988
44989         /* As with all inspection code, we rely on the debug client providing
44990          * a valid, non-stale pointer: there's no portable way to safely
44991          * validate the pointer here.
44992          */
44993
44994         duk__debug_getinfo_flags_key(thr, "heapptr");
44995         duk_debug_write_heapptr(thr, h);
44996
44997         /* XXX: comes out as signed now */
44998         duk__debug_getinfo_prop_uint(thr, "heaphdr_flags", (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
44999         duk__debug_getinfo_prop_uint(thr, "heaphdr_type", (duk_uint_t) DUK_HEAPHDR_GET_TYPE(h));
45000 #if defined(DUK_USE_REFERENCE_COUNTING)
45001         duk__debug_getinfo_prop_uint(thr, "refcount", (duk_uint_t) DUK_HEAPHDR_GET_REFCOUNT(h));
45002 #endif
45003 #if 0 /* pruned */
45004         duk__debug_getinfo_bitmask(thr,
45005                                    duk__debug_getinfo_heaphdr_keys,
45006                                    duk__debug_getinfo_heaphdr_masks,
45007                                    DUK_HEAPHDR_GET_FLAGS_RAW(h));
45008 #endif
45009
45010         switch (DUK_HEAPHDR_GET_TYPE(h)) {
45011         case DUK_HTYPE_STRING: {
45012                 duk_hstring *h_str;
45013
45014                 h_str = (duk_hstring *) h;
45015                 duk__debug_getinfo_bitmask(thr,
45016                                            duk__debug_getinfo_hstring_keys,
45017                                            duk__debug_getinfo_hstring_masks,
45018                                            DUK_HEAPHDR_GET_FLAGS_RAW(h));
45019                 duk__debug_getinfo_prop_uint(thr, "bytelen", (duk_uint_t) DUK_HSTRING_GET_BYTELEN(h_str));
45020                 duk__debug_getinfo_prop_uint(thr, "charlen", (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_str));
45021                 duk__debug_getinfo_prop_uint(thr, "hash", (duk_uint_t) DUK_HSTRING_GET_HASH(h_str));
45022                 duk__debug_getinfo_flags_key(thr, "data");
45023                 duk_debug_write_hstring(thr, h_str);
45024                 break;
45025         }
45026         case DUK_HTYPE_OBJECT: {
45027                 duk_hobject *h_obj;
45028                 duk_hobject *h_proto;
45029
45030                 h_obj = (duk_hobject *) h;
45031                 h_proto = DUK_HOBJECT_GET_PROTOTYPE(heap, h_obj);
45032
45033                 /* duk_hobject specific fields. */
45034                 duk__debug_getinfo_bitmask(thr,
45035                                            duk__debug_getinfo_hobject_keys,
45036                                            duk__debug_getinfo_hobject_masks,
45037                                            DUK_HEAPHDR_GET_FLAGS_RAW(h));
45038                 duk__debug_getinfo_prop_uint(thr, "class_number", DUK_HOBJECT_GET_CLASS_NUMBER(h_obj));
45039                 duk__debug_getinfo_flags_key(thr, "class_name");
45040                 duk_debug_write_hstring(thr, DUK_HOBJECT_GET_CLASS_STRING(heap, h_obj));
45041                 duk__debug_getinfo_flags_key(thr, "prototype");
45042                 if (h_proto != NULL) {
45043                         duk_debug_write_hobject(thr, h_proto);
45044                 } else {
45045                         duk_debug_write_null(thr);
45046                 }
45047                 duk__debug_getinfo_flags_key(thr, "props");
45048                 duk_debug_write_pointer(thr, (void *) DUK_HOBJECT_GET_PROPS(heap, h_obj));
45049                 duk__debug_getinfo_prop_uint(thr, "e_size", (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
45050                 duk__debug_getinfo_prop_uint(thr, "e_next", (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
45051                 duk__debug_getinfo_prop_uint(thr, "a_size", (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
45052                 duk__debug_getinfo_prop_uint(thr, "h_size", (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
45053
45054                 if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
45055                         duk_harray *h_arr;
45056                         h_arr = (duk_harray *) h_obj;
45057
45058                         duk__debug_getinfo_prop_uint(thr, "length", (duk_uint_t) h_arr->length);
45059                         duk__debug_getinfo_prop_bool(thr, "length_nonwritable", h_arr->length_nonwritable);
45060                 }
45061
45062                 if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
45063                         duk_hnatfunc *h_fun;
45064                         h_fun = (duk_hnatfunc *) h_obj;
45065
45066                         duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
45067                         duk__debug_getinfo_prop_int(thr, "magic", h_fun->magic);
45068                         duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATFUNC_NARGS_VARARGS);
45069                         /* Native function pointer may be different from a void pointer,
45070                          * and we serialize it from memory directly now (no byte swapping etc).
45071                          */
45072                         duk__debug_getinfo_flags_key(thr, "funcptr");
45073                         duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func));
45074                 }
45075
45076                 if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
45077                         duk_hcompfunc *h_fun;
45078                         duk_hbuffer *h_buf;
45079                         duk_hobject *h_lexenv;
45080                         duk_hobject *h_varenv;
45081                         h_fun = (duk_hcompfunc *) h_obj;
45082
45083                         duk__debug_getinfo_prop_int(thr, "nregs", h_fun->nregs);
45084                         duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
45085
45086                         duk__debug_getinfo_flags_key(thr, "lex_env");
45087                         h_lexenv = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, h_fun);
45088                         if (h_lexenv != NULL) {
45089                                 duk_debug_write_hobject(thr, h_lexenv);
45090                         } else {
45091                                 duk_debug_write_null(thr);
45092                         }
45093                         duk__debug_getinfo_flags_key(thr, "var_env");
45094                         h_varenv = DUK_HCOMPFUNC_GET_VARENV(thr->heap, h_fun);
45095                         if (h_varenv != NULL) {
45096                                 duk_debug_write_hobject(thr, h_varenv);
45097                         } else {
45098                                 duk_debug_write_null(thr);
45099                         }
45100
45101                         duk__debug_getinfo_prop_uint(thr, "start_line", h_fun->start_line);
45102                         duk__debug_getinfo_prop_uint(thr, "end_line", h_fun->end_line);
45103                         h_buf = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun);
45104                         if (h_buf != NULL) {
45105                                 duk__debug_getinfo_flags_key(thr, "data");
45106                                 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf);
45107                         }
45108                 }
45109
45110                 if (DUK_HOBJECT_IS_BOUNDFUNC(h_obj)) {
45111                         duk_hboundfunc *h_bfun;
45112                         h_bfun = (duk_hboundfunc *) (void *) h_obj;
45113
45114                         duk__debug_getinfo_flags_key(thr, "target");
45115                         duk_debug_write_tval(thr, &h_bfun->target);
45116                         duk__debug_getinfo_flags_key(thr, "this_binding");
45117                         duk_debug_write_tval(thr, &h_bfun->this_binding);
45118                         duk__debug_getinfo_flags_key(thr, "nargs");
45119                         duk_debug_write_int(thr, h_bfun->nargs);
45120                         /* h_bfun->args not exposed now */
45121                 }
45122
45123                 if (DUK_HOBJECT_IS_THREAD(h_obj)) {
45124                         /* XXX: Currently no inspection of threads, e.g. value stack, call
45125                          * stack, catch stack, etc.
45126                          */
45127                         duk_hthread *h_thr;
45128                         h_thr = (duk_hthread *) h_obj;
45129                         DUK_UNREF(h_thr);
45130                 }
45131
45132                 if (DUK_HOBJECT_IS_DECENV(h_obj)) {
45133                         duk_hdecenv *h_env;
45134                         h_env = (duk_hdecenv *) h_obj;
45135
45136                         duk__debug_getinfo_flags_key(thr, "thread");
45137                         duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->thread));
45138                         duk__debug_getinfo_flags_key(thr, "varmap");
45139                         duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->varmap));
45140                         duk__debug_getinfo_prop_uint(thr, "regbase", (duk_uint_t) h_env->regbase_byteoff);
45141                 }
45142
45143                 if (DUK_HOBJECT_IS_OBJENV(h_obj)) {
45144                         duk_hobjenv *h_env;
45145                         h_env = (duk_hobjenv *) h_obj;
45146
45147                         duk__debug_getinfo_flags_key(thr, "target");
45148                         duk_debug_write_heapptr(thr, (duk_heaphdr *) (h_env->target));
45149                         duk__debug_getinfo_prop_bool(thr, "has_this", h_env->has_this);
45150                 }
45151
45152 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
45153                 if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
45154                         duk_hbufobj *h_bufobj;
45155                         h_bufobj = (duk_hbufobj *) h_obj;
45156
45157                         duk__debug_getinfo_prop_uint(thr, "slice_offset", h_bufobj->offset);
45158                         duk__debug_getinfo_prop_uint(thr, "slice_length", h_bufobj->length);
45159                         duk__debug_getinfo_prop_uint(thr, "elem_shift", (duk_uint_t) h_bufobj->shift);
45160                         duk__debug_getinfo_prop_uint(thr, "elem_type", (duk_uint_t) h_bufobj->elem_type);
45161                         duk__debug_getinfo_prop_bool(thr, "is_typedarray", (duk_uint_t) h_bufobj->is_typedarray);
45162                         if (h_bufobj->buf != NULL) {
45163                                 duk__debug_getinfo_flags_key(thr, "buffer");
45164                                 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf);
45165                         }
45166                 }
45167 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
45168                 break;
45169         }
45170         case DUK_HTYPE_BUFFER: {
45171                 duk_hbuffer *h_buf;
45172
45173                 h_buf = (duk_hbuffer *) h;
45174                 duk__debug_getinfo_bitmask(thr,
45175                                            duk__debug_getinfo_hbuffer_keys,
45176                                            duk__debug_getinfo_hbuffer_masks,
45177                                            DUK_HEAPHDR_GET_FLAGS_RAW(h));
45178                 duk__debug_getinfo_prop_uint(thr, "size", (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
45179                 duk__debug_getinfo_flags_key(thr, "dataptr");
45180                 duk_debug_write_pointer(thr, (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf));
45181                 duk__debug_getinfo_flags_key(thr, "data");
45182                 duk_debug_write_hbuffer(thr, h_buf);  /* tolerates NULL h_buf */
45183                 break;
45184         }
45185         default: {
45186                 /* Since we already started writing the reply, just emit nothing. */
45187                 DUK_D(DUK_DPRINT("inspect target pointer has invalid heaphdr type"));
45188         }
45189         }
45190
45191         duk_debug_write_eom(thr);
45192 }
45193
45194 DUK_LOCAL void duk__debug_handle_get_obj_prop_desc(duk_hthread *thr, duk_heap *heap) {
45195         duk_heaphdr *h;
45196         duk_hobject *h_obj;
45197         duk_hstring *h_key;
45198         duk_propdesc desc;
45199
45200         DUK_D(DUK_DPRINT("debug command GetObjPropDesc"));
45201         DUK_UNREF(heap);
45202
45203         h = duk_debug_read_any_ptr(thr);
45204         if (!h) {
45205                 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
45206                 return;
45207         }
45208         h_key = duk_debug_read_hstring(thr);
45209         if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT || h_key == NULL) {
45210                 goto fail_args;
45211         }
45212         h_obj = (duk_hobject *) h;
45213
45214         if (duk_hobject_get_own_propdesc(thr, h_obj, h_key, &desc, 0 /*flags*/)) {
45215                 duk_int_t virtual_idx;
45216                 duk_bool_t rc;
45217
45218                 /* To use the shared helper need the virtual index. */
45219                 DUK_ASSERT(desc.e_idx >= 0 || desc.a_idx >= 0);
45220                 virtual_idx = (desc.a_idx >= 0 ? desc.a_idx :
45221                                (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj) + desc.e_idx);
45222
45223                 duk_debug_write_reply(thr);
45224                 rc = duk__debug_getprop_index(thr, heap, h_obj, (duk_uint_t) virtual_idx);
45225                 DUK_ASSERT(rc == 1);
45226                 DUK_UNREF(rc);
45227                 duk_debug_write_eom(thr);
45228         } else {
45229                 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "not found");
45230         }
45231         return;
45232
45233  fail_args:
45234         duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
45235 }
45236
45237 DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_heap *heap) {
45238         duk_heaphdr *h;
45239         duk_hobject *h_obj;
45240         duk_uint_t idx, idx_start, idx_end;
45241
45242         DUK_D(DUK_DPRINT("debug command GetObjPropDescRange"));
45243         DUK_UNREF(heap);
45244
45245         h = duk_debug_read_any_ptr(thr);
45246         idx_start = (duk_uint_t) duk_debug_read_int(thr);
45247         idx_end = (duk_uint_t) duk_debug_read_int(thr);
45248         if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) {
45249                 goto fail_args;
45250         }
45251         h_obj = (duk_hobject *) h;
45252
45253         /* The index range space is conceptually the array part followed by the
45254          * entry part.  Unlike normal enumeration all slots are exposed here as
45255          * is and return 'unused' if the slots are not in active use.  In particular
45256          * the array part is included for the full a_size regardless of what the
45257          * array .length is.
45258          */
45259
45260         duk_debug_write_reply(thr);
45261         for (idx = idx_start; idx < idx_end; idx++) {
45262                 if (!duk__debug_getprop_index(thr, heap, h_obj, idx)) {
45263                         break;
45264                 }
45265         }
45266         duk_debug_write_eom(thr);
45267         return;
45268
45269  fail_args:
45270         duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
45271 }
45272
45273 #endif  /* DUK_USE_DEBUGGER_INSPECT */
45274
45275 /*
45276  *  Process incoming debug requests
45277  *
45278  *  Individual request handlers can push temporaries on the value stack and
45279  *  rely on duk__debug_process_message() to restore the value stack top
45280  *  automatically.
45281  */
45282
45283 /* Process one debug message.  Automatically restore value stack top to its
45284  * entry value, so that individual message handlers don't need exact value
45285  * stack handling which is convenient.
45286  */
45287 DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
45288         duk_heap *heap;
45289         duk_uint8_t x;
45290         duk_int32_t cmd;
45291         duk_idx_t entry_top;
45292
45293         DUK_ASSERT(thr != NULL);
45294         heap = thr->heap;
45295         DUK_ASSERT(heap != NULL);
45296
45297         entry_top = duk_get_top(thr);
45298
45299         x = duk_debug_read_byte(thr);
45300         switch (x) {
45301         case DUK_DBG_IB_REQUEST: {
45302                 cmd = duk_debug_read_int(thr);
45303                 switch (cmd) {
45304                 case DUK_DBG_CMD_BASICINFO: {
45305                         duk__debug_handle_basic_info(thr, heap);
45306                         break;
45307                 }
45308                 case DUK_DBG_CMD_TRIGGERSTATUS: {
45309                         duk__debug_handle_trigger_status(thr, heap);
45310                         break;
45311                 }
45312                 case DUK_DBG_CMD_PAUSE: {
45313                         duk__debug_handle_pause(thr, heap);
45314                         break;
45315                 }
45316                 case DUK_DBG_CMD_RESUME: {
45317                         duk__debug_handle_resume(thr, heap);
45318                         break;
45319                 }
45320                 case DUK_DBG_CMD_STEPINTO:
45321                 case DUK_DBG_CMD_STEPOVER:
45322                 case DUK_DBG_CMD_STEPOUT: {
45323                         duk__debug_handle_step(thr, heap, cmd);
45324                         break;
45325                 }
45326                 case DUK_DBG_CMD_LISTBREAK: {
45327                         duk__debug_handle_list_break(thr, heap);
45328                         break;
45329                 }
45330                 case DUK_DBG_CMD_ADDBREAK: {
45331                         duk__debug_handle_add_break(thr, heap);
45332                         break;
45333                 }
45334                 case DUK_DBG_CMD_DELBREAK: {
45335                         duk__debug_handle_del_break(thr, heap);
45336                         break;
45337                 }
45338                 case DUK_DBG_CMD_GETVAR: {
45339                         duk__debug_handle_get_var(thr, heap);
45340                         break;
45341                 }
45342                 case DUK_DBG_CMD_PUTVAR: {
45343                         duk__debug_handle_put_var(thr, heap);
45344                         break;
45345                 }
45346                 case DUK_DBG_CMD_GETCALLSTACK: {
45347                         duk__debug_handle_get_call_stack(thr, heap);
45348                         break;
45349                 }
45350                 case DUK_DBG_CMD_GETLOCALS: {
45351                         duk__debug_handle_get_locals(thr, heap);
45352                         break;
45353                 }
45354                 case DUK_DBG_CMD_EVAL: {
45355                         duk__debug_handle_eval(thr, heap);
45356                         break;
45357                 }
45358                 case DUK_DBG_CMD_DETACH: {
45359                         /* The actual detached_cb call is postponed to message loop so
45360                          * we don't need any special precautions here (just skip to EOM
45361                          * on the already closed connection).
45362                          */
45363                         duk__debug_handle_detach(thr, heap);
45364                         break;
45365                 }
45366 #if defined(DUK_USE_DEBUGGER_DUMPHEAP)
45367                 case DUK_DBG_CMD_DUMPHEAP: {
45368                         duk__debug_handle_dump_heap(thr, heap);
45369                         break;
45370                 }
45371 #endif  /* DUK_USE_DEBUGGER_DUMPHEAP */
45372                 case DUK_DBG_CMD_GETBYTECODE: {
45373                         duk__debug_handle_get_bytecode(thr, heap);
45374                         break;
45375                 }
45376                 case DUK_DBG_CMD_APPREQUEST: {
45377                         duk__debug_handle_apprequest(thr, heap);
45378                         break;
45379                 }
45380 #if defined(DUK_USE_DEBUGGER_INSPECT)
45381                 case DUK_DBG_CMD_GETHEAPOBJINFO: {
45382                         duk__debug_handle_get_heap_obj_info(thr, heap);
45383                         break;
45384                 }
45385                 case DUK_DBG_CMD_GETOBJPROPDESC: {
45386                         duk__debug_handle_get_obj_prop_desc(thr, heap);
45387                         break;
45388                 }
45389                 case DUK_DBG_CMD_GETOBJPROPDESCRANGE: {
45390                         duk__debug_handle_get_obj_prop_desc_range(thr, heap);
45391                         break;
45392                 }
45393 #endif  /* DUK_USE_DEBUGGER_INSPECT */
45394                 default: {
45395                         DUK_D(DUK_DPRINT("debug command unsupported: %d", (int) cmd));
45396                         duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command");
45397                 }
45398                 }  /* switch cmd */
45399                 break;
45400         }
45401         case DUK_DBG_IB_REPLY: {
45402                 DUK_D(DUK_DPRINT("debug reply, skipping"));
45403                 break;
45404         }
45405         case DUK_DBG_IB_ERROR: {
45406                 DUK_D(DUK_DPRINT("debug error, skipping"));
45407                 break;
45408         }
45409         case DUK_DBG_IB_NOTIFY: {
45410                 DUK_D(DUK_DPRINT("debug notify, skipping"));
45411                 break;
45412         }
45413         default: {
45414                 DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x));
45415                 goto fail;
45416         }
45417         }  /* switch initial byte */
45418
45419         DUK_ASSERT(duk_get_top(thr) >= entry_top);
45420         duk_set_top(thr, entry_top);
45421         duk__debug_skip_to_eom(thr);
45422         return;
45423
45424  fail:
45425         DUK_ASSERT(duk_get_top(thr) >= entry_top);
45426         duk_set_top(thr, entry_top);
45427         DUK__SET_CONN_BROKEN(thr, 1);
45428         return;
45429 }
45430
45431 DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) {
45432         if (thr->heap->dbg_read_cb != NULL && thr->heap->dbg_state_dirty) {
45433                 duk_debug_send_status(thr);
45434                 thr->heap->dbg_state_dirty = 0;
45435         }
45436 }
45437
45438 DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
45439 #if defined(DUK_USE_ASSERTIONS)
45440         duk_idx_t entry_top;
45441 #endif
45442         duk_bool_t retval = 0;
45443
45444         DUK_ASSERT(thr != NULL);
45445         DUK_ASSERT(thr->heap != NULL);
45446 #if defined(DUK_USE_ASSERTIONS)
45447         entry_top = duk_get_top(thr);
45448 #endif
45449
45450         DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld",
45451                          thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block,
45452                          (long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing));
45453         DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(thr)));
45454
45455         /* thr->heap->dbg_detaching may be != 0 if a debugger write outside
45456          * the message loop caused a transport error and detach1() to run.
45457          */
45458         DUK_ASSERT(thr->heap->dbg_detaching == 0 || thr->heap->dbg_detaching == 1);
45459         DUK_ASSERT(thr->heap->dbg_processing == 0);
45460         thr->heap->dbg_processing = 1;
45461
45462         /* Ensure dirty state causes a Status even if never process any
45463          * messages.  This is expected by the bytecode executor when in
45464          * the running state.
45465          */
45466         duk__check_resend_status(thr);
45467
45468         for (;;) {
45469                 /* Process messages until we're no longer paused or we peek
45470                  * and see there's nothing to read right now.
45471                  */
45472                 DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(thr)));
45473                 DUK_ASSERT(thr->heap->dbg_processing == 1);
45474
45475                 while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) {
45476                         /* Detach is pending; can be triggered from outside the
45477                          * debugger loop (e.g. Status notify write error) or by
45478                          * previous message handling.  Call detached callback
45479                          * here, in a controlled state, to ensure a possible
45480                          * reattach inside the detached_cb is handled correctly.
45481                          *
45482                          * Recheck for detach in a while loop: an immediate
45483                          * reattach involves a call to duk_debugger_attach()
45484                          * which writes a debugger handshake line immediately
45485                          * inside the API call.  If the transport write fails
45486                          * for that handshake, we can immediately end up in a
45487                          * "transport broken, detaching" case several times here.
45488                          * Loop back until we're either cleanly attached or
45489                          * fully detached.
45490                          *
45491                          * NOTE: Reset dbg_processing = 1 forcibly, in case we
45492                          * re-attached; duk_debugger_attach() sets dbg_processing
45493                          * to 0 at the moment.
45494                          */
45495
45496                         DUK_D(DUK_DPRINT("detach pending (dbg_read_cb == NULL, dbg_detaching != 0), call detach2"));
45497
45498                         duk__debug_do_detach2(thr->heap);
45499                         thr->heap->dbg_processing = 1;  /* may be set to 0 by duk_debugger_attach() inside callback */
45500
45501                         DUK_D(DUK_DPRINT("after detach2 (and possible reattach): dbg_read_cb=%s, dbg_detaching=%ld",
45502                                          thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) thr->heap->dbg_detaching));
45503                 }
45504                 DUK_ASSERT(thr->heap->dbg_detaching == 0);  /* true even with reattach */
45505                 DUK_ASSERT(thr->heap->dbg_processing == 1);  /* even after a detach and possible reattach */
45506
45507                 if (thr->heap->dbg_read_cb == NULL) {
45508                         DUK_D(DUK_DPRINT("debug connection broken (and not detaching), stop processing messages"));
45509                         break;
45510                 }
45511
45512                 if (!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || no_block) {
45513                         if (!duk_debug_read_peek(thr)) {
45514                                 /* Note: peek cannot currently trigger a detach
45515                                  * so the dbg_detaching == 0 assert outside the
45516                                  * loop is correct.
45517                                  */
45518                                 DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing messages"));
45519                                 break;
45520                         }
45521                         DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it"));
45522                 } else {
45523                         DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary"));
45524                 }
45525
45526                 duk__check_resend_status(thr);
45527                 duk__debug_process_message(thr);
45528                 duk__check_resend_status(thr);
45529
45530                 retval = 1;  /* processed one or more messages */
45531         }
45532
45533         DUK_ASSERT(thr->heap->dbg_detaching == 0);
45534         DUK_ASSERT(thr->heap->dbg_processing == 1);
45535         thr->heap->dbg_processing = 0;
45536
45537         /* As an initial implementation, read flush after exiting the message
45538          * loop.  If transport is broken, this is a no-op (with debug logs).
45539          */
45540         duk_debug_read_flush(thr);  /* this cannot initiate a detach */
45541         DUK_ASSERT(thr->heap->dbg_detaching == 0);
45542
45543         DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(thr)));
45544
45545 #if defined(DUK_USE_ASSERTIONS)
45546         /* Easy to get wrong, so assert for it. */
45547         DUK_ASSERT(entry_top == duk_get_top(thr));
45548 #endif
45549
45550         return retval;
45551 }
45552
45553 /*
45554  *  Halt execution helper
45555  */
45556
45557 /* Halt execution and enter a debugger message loop until execution is resumed
45558  * by the client.  PC for the current activation may be temporarily decremented
45559  * so that the "current" instruction will be shown by the client.  This helper
45560  * is callable from anywhere, also outside bytecode executor.
45561  */
45562
45563 DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) {
45564         duk_activation *act;
45565         duk_hcompfunc *fun;
45566         duk_instr_t *old_pc = NULL;
45567
45568         DUK_ASSERT(thr != NULL);
45569         DUK_ASSERT(thr->heap != NULL);
45570         DUK_ASSERT(duk_debug_is_attached(thr->heap));
45571         DUK_ASSERT(thr->heap->dbg_processing == 0);
45572         DUK_ASSERT(!duk_debug_is_paused(thr->heap));
45573
45574         duk_debug_set_paused(thr->heap);
45575
45576         act = thr->callstack_curr;
45577
45578         /* NOTE: act may be NULL if an error is thrown outside of any activation,
45579          * which may happen in the case of, e.g. syntax errors.
45580          */
45581
45582         /* Decrement PC if that was requested, this requires a PC sync. */
45583         if (act != NULL) {
45584                 duk_hthread_sync_currpc(thr);
45585                 old_pc = act->curr_pc;
45586                 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
45587
45588                 /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is
45589                  * guaranteed to be a non-NULL ECMAScript function.
45590                  */
45591                 DUK_ASSERT(act->curr_pc == NULL ||
45592                            (fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)));
45593                 if (use_prev_pc &&
45594                     act->curr_pc != NULL &&
45595                     act->curr_pc > DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, fun)) {
45596                         act->curr_pc--;
45597                 }
45598         }
45599
45600         /* Process debug messages until we are no longer paused. */
45601
45602         /* NOTE: This is a bit fragile.  It's important to ensure that
45603          * duk_debug_process_messages() never throws an error or
45604          * act->curr_pc will never be reset.
45605          */
45606
45607         thr->heap->dbg_state_dirty = 1;
45608         while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
45609                 DUK_ASSERT(duk_debug_is_attached(thr->heap));
45610                 DUK_ASSERT(thr->heap->dbg_processing == 0);
45611                 duk_debug_process_messages(thr, 0 /*no_block*/);
45612         }
45613
45614         /* XXX: Decrementing and restoring act->curr_pc works now, but if the
45615          * debugger message loop gains the ability to adjust the current PC
45616          * (e.g. a forced jump) restoring the PC here will break.  Another
45617          * approach would be to use a state flag for the "decrement 1 from
45618          * topmost activation's PC" and take it into account whenever dealing
45619          * with PC values.
45620          */
45621         if (act != NULL) {
45622                 act->curr_pc = old_pc;  /* restore PC */
45623         }
45624 }
45625
45626 /*
45627  *  Breakpoint management
45628  */
45629
45630 DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) {
45631         duk_heap *heap;
45632         duk_breakpoint *b;
45633
45634         /* Caller must trigger recomputation of active breakpoint list.  To
45635          * ensure stale values are not used if that doesn't happen, clear the
45636          * active breakpoint list here.
45637          */
45638
45639         DUK_ASSERT(thr != NULL);
45640         DUK_ASSERT(filename != NULL);
45641         heap = thr->heap;
45642         DUK_ASSERT(heap != NULL);
45643
45644         if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) {
45645                 DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used",
45646                                  (duk_heaphdr *) filename, (long) line));
45647                 return -1;
45648         }
45649         heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
45650         b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++);
45651         b->filename = filename;
45652         b->line = line;
45653         DUK_HSTRING_INCREF(thr, filename);
45654
45655         return (duk_small_int_t) (heap->dbg_breakpoint_count - 1);  /* index */
45656 }
45657
45658 DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
45659         duk_heap *heap;
45660         duk_hstring *h;
45661         duk_breakpoint *b;
45662         duk_size_t move_size;
45663
45664         /* Caller must trigger recomputation of active breakpoint list.  To
45665          * ensure stale values are not used if that doesn't happen, clear the
45666          * active breakpoint list here.
45667          */
45668
45669         DUK_ASSERT(thr != NULL);
45670         heap = thr->heap;
45671         DUK_ASSERT(heap != NULL);
45672         DUK_ASSERT(duk_debug_is_attached(thr->heap));
45673         DUK_ASSERT_DISABLE(breakpoint_index >= 0);  /* unsigned */
45674
45675         if (breakpoint_index >= heap->dbg_breakpoint_count) {
45676                 DUK_D(DUK_DPRINT("invalid breakpoint index: %ld", (long) breakpoint_index));
45677                 return 0;
45678         }
45679         b = heap->dbg_breakpoints + breakpoint_index;
45680
45681         h = b->filename;
45682         DUK_ASSERT(h != NULL);
45683
45684         move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
45685         duk_memmove((void *) b,
45686                     (const void *) (b + 1),
45687                     (size_t) move_size);
45688
45689         heap->dbg_breakpoint_count--;
45690         heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
45691
45692         DUK_HSTRING_DECREF(thr, h);  /* side effects */
45693         DUK_UNREF(h);  /* w/o refcounting */
45694
45695         /* Breakpoint entries above the used area are left as garbage. */
45696
45697         return 1;
45698 }
45699
45700 /*
45701  *  Misc state management
45702  */
45703
45704 DUK_INTERNAL duk_bool_t duk_debug_is_attached(duk_heap *heap) {
45705         return (heap->dbg_read_cb != NULL);
45706 }
45707
45708 DUK_INTERNAL duk_bool_t duk_debug_is_paused(duk_heap *heap) {
45709         return (DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) != 0);
45710 }
45711
45712 DUK_INTERNAL void duk_debug_set_paused(duk_heap *heap) {
45713         if (duk_debug_is_paused(heap)) {
45714                 DUK_D(DUK_DPRINT("trying to set paused state when already paused, ignoring"));
45715         } else {
45716                 DUK_HEAP_SET_DEBUGGER_PAUSED(heap);
45717                 heap->dbg_state_dirty = 1;
45718                 duk_debug_clear_pause_state(heap);
45719                 DUK_ASSERT(heap->ms_running == 0);  /* debugger can't be triggered within mark-and-sweep */
45720                 heap->ms_running = 1;  /* prevent mark-and-sweep, prevent refzero queueing */
45721                 heap->ms_prevent_count++;
45722                 DUK_ASSERT(heap->ms_prevent_count != 0);  /* Wrap. */
45723                 DUK_ASSERT(heap->heap_thread != NULL);
45724         }
45725 }
45726
45727 DUK_INTERNAL void duk_debug_clear_paused(duk_heap *heap) {
45728         if (duk_debug_is_paused(heap)) {
45729                 DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap);
45730                 heap->dbg_state_dirty = 1;
45731                 duk_debug_clear_pause_state(heap);
45732                 DUK_ASSERT(heap->ms_running == 1);
45733                 DUK_ASSERT(heap->ms_prevent_count > 0);
45734                 heap->ms_prevent_count--;
45735                 heap->ms_running = 0;
45736                 DUK_ASSERT(heap->heap_thread != NULL);
45737         } else {
45738                 DUK_D(DUK_DPRINT("trying to clear paused state when not paused, ignoring"));
45739         }
45740 }
45741
45742 DUK_INTERNAL void duk_debug_clear_pause_state(duk_heap *heap) {
45743         heap->dbg_pause_flags = 0;
45744         heap->dbg_pause_act = NULL;
45745         heap->dbg_pause_startline = 0;
45746 }
45747
45748 #else  /* DUK_USE_DEBUGGER_SUPPORT */
45749
45750 /* No debugger support. */
45751
45752 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
45753
45754 /* automatic undefs */
45755 #undef DUK__DBG_TPORT_ENTER
45756 #undef DUK__DBG_TPORT_EXIT
45757 #undef DUK__SET_CONN_BROKEN
45758 #line 1 "duk_error_augment.c"
45759 /*
45760  *  Augmenting errors at their creation site and their throw site.
45761  *
45762  *  When errors are created, traceback data is added by built-in code
45763  *  and a user error handler (if defined) can process or replace the
45764  *  error.  Similarly, when errors are thrown, a user error handler
45765  *  (if defined) can process or replace the error.
45766  *
45767  *  Augmentation and other processing at error creation time is nice
45768  *  because an error is only created once, but it may be thrown and
45769  *  rethrown multiple times.  User error handler registered for processing
45770  *  an error at its throw site must be careful to handle rethrowing in
45771  *  a useful manner.
45772  *
45773  *  Error augmentation may throw an internal error (e.g. alloc error).
45774  *
45775  *  ECMAScript allows throwing any values, so all values cannot be
45776  *  augmented.  Currently, the built-in augmentation at error creation
45777  *  only augments error values which are Error instances (= have the
45778  *  built-in Error.prototype in their prototype chain) and are also
45779  *  extensible.  User error handlers have no limitations in this respect.
45780  */
45781
45782 /* #include duk_internal.h -> already included */
45783
45784 /*
45785  *  Helper for calling a user error handler.
45786  *
45787  *  'thr' must be the currently active thread; the error handler is called
45788  *  in its context.  The valstack of 'thr' must have the error value on
45789  *  top, and will be replaced by another error value based on the return
45790  *  value of the error handler.
45791  *
45792  *  The helper calls duk_handle_call() recursively in protected mode.
45793  *  Before that call happens, no longjmps should happen; as a consequence,
45794  *  we must assume that the valstack contains enough temporary space for
45795  *  arguments and such.
45796  *
45797  *  While the error handler runs, any errors thrown will not trigger a
45798  *  recursive error handler call (this is implemented using a heap level
45799  *  flag which will "follow" through any coroutines resumed inside the
45800  *  error handler).  If the error handler is not callable or throws an
45801  *  error, the resulting error replaces the original error (for Duktape
45802  *  internal errors, duk_error_throw.c further substitutes this error with
45803  *  a DoubleError which is not ideal).  This would be easy to change and
45804  *  even signal to the caller.
45805  *
45806  *  The user error handler is stored in 'Duktape.errCreate' or
45807  *  'Duktape.errThrow' depending on whether we're augmenting the error at
45808  *  creation or throw time.  There are several alternatives to this approach,
45809  *  see doc/error-objects.rst for discussion.
45810  *
45811  *  Note: since further longjmp()s may occur while calling the error handler
45812  *  (for many reasons, e.g. a labeled 'break' inside the handler), the
45813  *  caller can make no assumptions on the thr->heap->lj state after the
45814  *  call (this affects especially duk_error_throw.c).  This is not an issue
45815  *  as long as the caller writes to the lj state only after the error handler
45816  *  finishes.
45817  */
45818
45819 #if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
45820 DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
45821         duk_tval *tv_hnd;
45822         duk_int_t rc;
45823
45824         DUK_ASSERT(thr != NULL);
45825         DUK_ASSERT(thr->heap != NULL);
45826         DUK_ASSERT_STRIDX_VALID(stridx_cb);
45827
45828         if (thr->heap->augmenting_error) {
45829                 DUK_D(DUK_DPRINT("recursive call to error augmentation, ignore"));
45830                 return;
45831         }
45832
45833         /*
45834          *  Check whether or not we have an error handler.
45835          *
45836          *  We must be careful of not triggering an error when looking up the
45837          *  property.  For instance, if the property is a getter, we don't want
45838          *  to call it, only plain values are allowed.  The value, if it exists,
45839          *  is not checked.  If the value is not a function, a TypeError happens
45840          *  when it is called and that error replaces the original one.
45841          */
45842
45843         DUK_ASSERT_VALSTACK_SPACE(thr, 4);  /* 3 entries actually needed below */
45844
45845         /* [ ... errval ] */
45846
45847         if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
45848                 /* When creating built-ins, some of the built-ins may not be set
45849                  * and we want to tolerate that when throwing errors.
45850                  */
45851                 DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring"));
45852                 return;
45853         }
45854         tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->heap,
45855                                                           thr->builtins[DUK_BIDX_DUKTAPE],
45856                                                           DUK_HTHREAD_GET_STRING(thr, stridx_cb));
45857         if (tv_hnd == NULL) {
45858                 DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T",
45859                                    (duk_tval *) tv_hnd));
45860                 return;
45861         }
45862         DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
45863                              (duk_tval *) tv_hnd));
45864         duk_push_tval(thr, tv_hnd);
45865
45866         /* [ ... errval errhandler ] */
45867
45868         duk_insert(thr, -2);  /* -> [ ... errhandler errval ] */
45869         duk_push_undefined(thr);
45870         duk_insert(thr, -2);  /* -> [ ... errhandler undefined(= this) errval ] */
45871
45872         /* [ ... errhandler undefined errval ] */
45873
45874         /*
45875          *  heap->augmenting_error prevents recursive re-entry and also causes
45876          *  call handling to use a larger (but not unbounded) call stack limit
45877          *  for the duration of error augmentation.
45878          *
45879          *  We ignore errors now: a success return and an error value both
45880          *  replace the original error value.  (This would be easy to change.)
45881          */
45882
45883         DUK_ASSERT(thr->heap->augmenting_error == 0);
45884         thr->heap->augmenting_error = 1;
45885
45886         rc = duk_pcall_method(thr, 1);
45887         DUK_UNREF(rc);  /* no need to check now: both success and error are OK */
45888
45889         DUK_ASSERT(thr->heap->augmenting_error == 1);
45890         thr->heap->augmenting_error = 0;
45891
45892         /* [ ... errval ] */
45893 }
45894 #endif  /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */
45895
45896 /*
45897  *  Add ._Tracedata to an error on the stack top.
45898  */
45899
45900 #if defined(DUK_USE_TRACEBACKS)
45901 DUK_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) {
45902         duk_activation *act;
45903         duk_int_t depth;
45904         duk_int_t arr_size;
45905         duk_tval *tv;
45906         duk_hstring *s;
45907         duk_uint32_t u32;
45908         duk_double_t d;
45909
45910         DUK_ASSERT(thr != NULL);
45911         DUK_ASSERT(thr_callstack != NULL);
45912
45913         /* [ ... error ] */
45914
45915         /*
45916          *  The traceback format is pretty arcane in an attempt to keep it compact
45917          *  and cheap to create.  It may change arbitrarily from version to version.
45918          *  It should be decoded/accessed through version specific accessors only.
45919          *
45920          *  See doc/error-objects.rst.
45921          */
45922
45923         DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
45924                              (duk_tval *) duk_get_tval(thr, -1)));
45925
45926         /* Preallocate array to correct size, so that we can just write out
45927          * the _Tracedata values into the array part.
45928          */
45929         act = thr->callstack_curr;
45930         depth = DUK_USE_TRACEBACK_DEPTH;
45931         DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX);  /* callstack limits */
45932         if (depth > (duk_int_t) thr_callstack->callstack_top) {
45933                 depth = (duk_int_t) thr_callstack->callstack_top;
45934         }
45935         if (depth > 0) {
45936                 if (flags & DUK_AUGMENT_FLAG_SKIP_ONE) {
45937                         DUK_ASSERT(act != NULL);
45938                         act = act->parent;
45939                         depth--;
45940                 }
45941         }
45942         arr_size = depth * 2;
45943         if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
45944                 arr_size += 2;
45945         }
45946         if (c_filename) {
45947                 /* We need the C filename to be interned before getting the
45948                  * array part pointer to avoid any GC interference while the
45949                  * array part is populated.
45950                  */
45951                 duk_push_string(thr, c_filename);
45952                 arr_size += 2;
45953         }
45954
45955         /* XXX: uninitialized would be OK */
45956         DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items", (long) arr_size));
45957         tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) arr_size);
45958         DUK_ASSERT(arr_size == 0 || tv != NULL);
45959
45960         /* Compiler SyntaxErrors (and other errors) come first, and are
45961          * blamed by default (not flagged "noblame").
45962          */
45963         if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
45964                 s = thr->compile_ctx->h_filename;
45965                 DUK_TVAL_SET_STRING(tv, s);
45966                 DUK_HSTRING_INCREF(thr, s);
45967                 tv++;
45968
45969                 u32 = (duk_uint32_t) thr->compile_ctx->curr_token.start_line;  /* (flags<<32) + (line), flags = 0 */
45970                 DUK_TVAL_SET_U32(tv, u32);
45971                 tv++;
45972         }
45973
45974         /* Filename/line from C macros (__FILE__, __LINE__) are added as an
45975          * entry with a special format: (string, number).  The number contains
45976          * the line and flags.
45977          */
45978
45979         /* [ ... error c_filename? arr ] */
45980
45981         if (c_filename) {
45982                 DUK_ASSERT(DUK_TVAL_IS_STRING(thr->valstack_top - 2));
45983                 s = DUK_TVAL_GET_STRING(thr->valstack_top - 2);  /* interned c_filename */
45984                 DUK_ASSERT(s != NULL);
45985                 DUK_TVAL_SET_STRING(tv, s);
45986                 DUK_HSTRING_INCREF(thr, s);
45987                 tv++;
45988
45989                 d = ((flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
45990                     (duk_double_t) c_line;
45991                 DUK_TVAL_SET_DOUBLE(tv, d);
45992                 tv++;
45993         }
45994
45995         /* Traceback depth doesn't take into account the filename/line
45996          * special handling above (intentional).
45997          */
45998         for (; depth-- > 0; act = act->parent) {
45999                 duk_uint32_t pc;
46000                 duk_tval *tv_src;
46001
46002                 /* [... arr] */
46003
46004                 DUK_ASSERT(act != NULL);  /* depth check above, assumes book-keeping is correct */
46005                 DUK_ASSERT_DISABLE(act->pc >= 0);  /* unsigned */
46006
46007                 /* Add function object. */
46008                 tv_src = &act->tv_func;  /* object (function) or lightfunc */
46009                 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src));
46010                 DUK_TVAL_SET_TVAL(tv, tv_src);
46011                 DUK_TVAL_INCREF(thr, tv);
46012                 tv++;
46013
46014                 /* Add a number containing: pc, activation flags.
46015                  *
46016                  * PC points to next instruction, find offending PC.  Note that
46017                  * PC == 0 for native code.
46018                  */
46019                 pc = (duk_uint32_t) duk_hthread_get_act_prev_pc(thr_callstack, act);
46020                 DUK_ASSERT_DISABLE(pc >= 0);  /* unsigned */
46021                 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32);  /* assume PC is at most 32 bits and non-negative */
46022                 d = ((duk_double_t) act->flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
46023                 DUK_TVAL_SET_DOUBLE(tv, d);
46024                 tv++;
46025         }
46026
46027 #if defined(DUK_USE_ASSERTIONS)
46028         {
46029                 duk_harray *a;
46030                 a = (duk_harray *) duk_known_hobject(thr, -1);
46031                 DUK_ASSERT(a != NULL);
46032                 DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length);
46033                 DUK_ASSERT(a->length == (duk_uint32_t) arr_size);
46034         }
46035 #endif
46036
46037         /* [ ... error c_filename? arr ] */
46038
46039         if (c_filename) {
46040                 duk_remove_m2(thr);
46041         }
46042
46043         /* [ ... error arr ] */
46044
46045         duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INT_TRACEDATA);  /* -> [ ... error ] */
46046 }
46047 #endif  /* DUK_USE_TRACEBACKS */
46048
46049 /*
46050  *  Add .fileName and .lineNumber to an error on the stack top.
46051  */
46052
46053 #if defined(DUK_USE_AUGMENT_ERROR_CREATE) && !defined(DUK_USE_TRACEBACKS)
46054 DUK_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) {
46055 #if defined(DUK_USE_ASSERTIONS)
46056         duk_int_t entry_top;
46057 #endif
46058
46059 #if defined(DUK_USE_ASSERTIONS)
46060         entry_top = duk_get_top(thr);
46061 #endif
46062
46063         /*
46064          *  If tracebacks are disabled, 'fileName' and 'lineNumber' are added
46065          *  as plain own properties.  Since Error.prototype has accessors of
46066          *  the same name, we need to define own properties directly (cannot
46067          *  just use e.g. duk_put_prop_stridx).  Existing properties are not
46068          *  overwritten in case they already exist.
46069          */
46070
46071         if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
46072                 /* Compiler SyntaxError (or other error) gets the primary blame.
46073                  * Currently no flag to prevent blaming.
46074                  */
46075                 duk_push_uint(thr, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
46076                 duk_push_hstring(thr, thr->compile_ctx->h_filename);
46077         } else if (c_filename && (flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE) == 0) {
46078                 /* C call site gets blamed next, unless flagged not to do so.
46079                  * XXX: file/line is disabled in minimal builds, so disable this
46080                  * too when appropriate.
46081                  */
46082                 duk_push_int(thr, c_line);
46083                 duk_push_string(thr, c_filename);
46084         } else {
46085                 /* Finally, blame the innermost callstack entry which has a
46086                  * .fileName property.
46087                  */
46088                 duk_small_uint_t depth;
46089                 duk_uint32_t ecma_line;
46090                 duk_activation *act;
46091
46092                 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX);  /* callstack limits */
46093                 depth = DUK_USE_TRACEBACK_DEPTH;
46094                 if (depth > thr_callstack->callstack_top) {
46095                         depth = thr_callstack->callstack_top;
46096                 }
46097                 for (act = thr_callstack->callstack_curr; depth-- > 0; act = act->parent) {
46098                         duk_hobject *func;
46099                         duk_uint32_t pc;
46100
46101                         DUK_ASSERT(act != NULL);
46102                         func = DUK_ACT_GET_FUNC(act);
46103                         if (func == NULL) {
46104                                 /* Lightfunc, not blamed now. */
46105                                 continue;
46106                         }
46107
46108                         /* PC points to next instruction, find offending PC,
46109                          * PC == 0 for native code.
46110                          */
46111                         pc = duk_hthread_get_act_prev_pc(thr, act);  /* thr argument only used for thr->heap, so specific thread doesn't matter */
46112                         DUK_UNREF(pc);
46113                         DUK_ASSERT_DISABLE(pc >= 0);  /* unsigned */
46114                         DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32);  /* assume PC is at most 32 bits and non-negative */
46115
46116                         duk_push_hobject(thr, func);
46117
46118                         /* [ ... error func ] */
46119
46120                         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_FILE_NAME);
46121                         if (!duk_is_string_notsymbol(thr, -1)) {
46122                                 duk_pop_2(thr);
46123                                 continue;
46124                         }
46125
46126                         /* [ ... error func fileName ] */
46127
46128                         ecma_line = 0;
46129 #if defined(DUK_USE_PC2LINE)
46130                         if (DUK_HOBJECT_IS_COMPFUNC(func)) {
46131                                 ecma_line = duk_hobject_pc2line_query(thr, -2, (duk_uint_fast32_t) pc);
46132                         } else {
46133                                 /* Native function, no relevant lineNumber. */
46134                         }
46135 #endif  /* DUK_USE_PC2LINE */
46136                         duk_push_u32(thr, ecma_line);
46137
46138                         /* [ ... error func fileName lineNumber ] */
46139
46140                         duk_replace(thr, -3);
46141
46142                         /* [ ... error lineNumber fileName ] */
46143                         goto define_props;
46144                 }
46145
46146                 /* No activation matches, use undefined for both .fileName and
46147                  * .lineNumber (matches what we do with a _Tracedata based
46148                  * no-match lookup.
46149                  */
46150                 duk_push_undefined(thr);
46151                 duk_push_undefined(thr);
46152         }
46153
46154  define_props:
46155         /* [ ... error lineNumber fileName ] */
46156 #if defined(DUK_USE_ASSERTIONS)
46157         DUK_ASSERT(duk_get_top(thr) == entry_top + 2);
46158 #endif
46159         duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
46160         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
46161 }
46162 #endif  /* DUK_USE_AUGMENT_ERROR_CREATE && !DUK_USE_TRACEBACKS */
46163
46164 /*
46165  *  Add line number to a compiler error.
46166  */
46167
46168 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
46169 DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
46170
46171         /* Append a "(line NNN)" to the "message" property of any error
46172          * thrown during compilation.  Usually compilation errors are
46173          * SyntaxErrors but they can also be out-of-memory errors and
46174          * the like.
46175          */
46176
46177         /* [ ... error ] */
46178
46179         DUK_ASSERT(duk_is_object(thr, -1));
46180
46181         if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
46182                 return;
46183         }
46184
46185         DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
46186                              (duk_tval *) duk_get_tval(thr, -1)));
46187
46188         if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_MESSAGE)) {
46189                 duk_push_sprintf(thr, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
46190                 duk_concat(thr, 2);
46191                 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_MESSAGE);
46192         } else {
46193                 duk_pop(thr);
46194         }
46195
46196         DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
46197                              (duk_tval *) duk_get_tval(thr, -1)));
46198 }
46199 #endif  /* DUK_USE_AUGMENT_ERROR_CREATE */
46200
46201 /*
46202  *  Augment an error being created using Duktape specific properties
46203  *  like _Tracedata or .fileName/.lineNumber.
46204  */
46205
46206 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
46207 DUK_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) {
46208 #if defined(DUK_USE_ASSERTIONS)
46209         duk_int_t entry_top;
46210 #endif
46211
46212 #if defined(DUK_USE_ASSERTIONS)
46213         entry_top = duk_get_top(thr);
46214 #endif
46215         DUK_ASSERT(obj != NULL);
46216
46217         DUK_UNREF(obj);  /* unreferenced w/o tracebacks */
46218
46219         duk__add_compiler_error_line(thr);
46220
46221 #if defined(DUK_USE_TRACEBACKS)
46222         /* If tracebacks are enabled, the '_Tracedata' property is the only
46223          * thing we need: 'fileName' and 'lineNumber' are virtual properties
46224          * which use '_Tracedata'.
46225          */
46226         if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) {
46227                 DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
46228         } else {
46229                 duk__add_traceback(thr, thr_callstack, c_filename, c_line, flags);
46230         }
46231 #else
46232         /* Without tracebacks the concrete .fileName and .lineNumber need
46233          * to be added directly.
46234          */
46235         duk__add_fileline(thr, thr_callstack, c_filename, c_line, flags);
46236 #endif
46237
46238 #if defined(DUK_USE_ASSERTIONS)
46239         DUK_ASSERT(duk_get_top(thr) == entry_top);
46240 #endif
46241 }
46242 #endif  /* DUK_USE_AUGMENT_ERROR_CREATE */
46243
46244 /*
46245  *  Augment an error at creation time with _Tracedata/fileName/lineNumber
46246  *  and allow a user error handler (if defined) to process/replace the error.
46247  *  The error to be augmented is at the stack top.
46248  *
46249  *  thr: thread containing the error value
46250  *  thr_callstack: thread which should be used for generating callstack etc.
46251  *  c_filename: C __FILE__ related to the error
46252  *  c_line: C __LINE__ related to the error
46253  *  flags & DUK_AUGMENT_FLAG_NOBLAME_FILELINE:
46254  *      if true, don't fileName/line as error source, otherwise use traceback
46255  *      (needed because user code filename/line are reported but internal ones
46256  *      are not)
46257  */
46258
46259 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
46260 DUK_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) {
46261         duk_hobject *obj;
46262
46263         DUK_ASSERT(thr != NULL);
46264         DUK_ASSERT(thr_callstack != NULL);
46265
46266         /* [ ... error ] */
46267
46268         /*
46269          *  Criteria for augmenting:
46270          *
46271          *   - augmentation enabled in build (naturally)
46272          *   - error value internal prototype chain contains the built-in
46273          *     Error prototype object (i.e. 'val instanceof Error')
46274          *
46275          *  Additional criteria for built-in augmenting:
46276          *
46277          *   - error value is an extensible object
46278          */
46279
46280         obj = duk_get_hobject(thr, -1);
46281         if (!obj) {
46282                 DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
46283                 return;
46284         }
46285         if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
46286                 /* If the value has a prototype loop, it's critical not to
46287                  * throw here.  Instead, assume the value is not to be
46288                  * augmented.
46289                  */
46290                 DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment"));
46291                 return;
46292         }
46293         if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
46294                 DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
46295                 duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, obj, flags);
46296         } else {
46297                 DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
46298         }
46299
46300         /* [ ... error ] */
46301
46302 #if defined(DUK_USE_ERRCREATE)
46303         duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE);
46304 #endif
46305 }
46306 #endif  /* DUK_USE_AUGMENT_ERROR_CREATE */
46307
46308 /*
46309  *  Augment an error at throw time; allow a user error handler (if defined)
46310  *  to process/replace the error.  The error to be augmented is at the
46311  *  stack top.
46312  */
46313
46314 #if defined(DUK_USE_AUGMENT_ERROR_THROW)
46315 DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
46316 #if defined(DUK_USE_ERRTHROW)
46317         duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW);
46318 #endif  /* DUK_USE_ERRTHROW */
46319 }
46320 #endif  /* DUK_USE_AUGMENT_ERROR_THROW */
46321 #line 1 "duk_error_longjmp.c"
46322 /*
46323  *  Do a longjmp call, calling the fatal error handler if no
46324  *  catchpoint exists.
46325  */
46326
46327 /* #include duk_internal.h -> already included */
46328
46329 #if defined(DUK_USE_PREFER_SIZE)
46330 DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_minimal(duk_hthread *thr));
46331 DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) {
46332         (void) duk_fatal(thr, "uncaught error");
46333         DUK_WO_NORETURN(return;);
46334 }
46335 #endif
46336
46337 #if 0
46338 DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_readable(duk_hthread *thr));
46339 DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) {
46340         const char *summary;
46341         char buf[DUK_USE_FATAL_MAXLEN];
46342
46343         summary = duk_push_string_tval_readable(thr, &thr->heap->lj.value1);
46344         DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
46345         buf[sizeof(buf) - 1] = (char) 0;
46346         (void) duk_fatal(thr, (const char *) buf);
46347         DUK_WO_NORETURN(return;);
46348 }
46349 #endif
46350
46351 #if !defined(DUK_USE_PREFER_SIZE)
46352 DUK_NORETURN(DUK_LOCAL_DECL void duk__uncaught_error_aware(duk_hthread *thr));
46353 DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) {
46354         const char *summary;
46355         char buf[DUK_USE_FATAL_MAXLEN];
46356
46357         summary = duk_push_string_tval_readable_error(thr, &thr->heap->lj.value1);
46358         DUK_ASSERT(summary != NULL);
46359         DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
46360         buf[sizeof(buf) - 1] = (char) 0;
46361         (void) duk_fatal(thr, (const char *) buf);
46362         DUK_WO_NORETURN(return;);
46363 }
46364 #endif
46365
46366 DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
46367         DUK_ASSERT(thr != NULL);
46368         DUK_ASSERT(thr->heap != NULL);
46369
46370         DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T",
46371                            (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
46372                            &thr->heap->lj.value1, &thr->heap->lj.value2));
46373
46374         /* Prevent finalizer execution during error handling.  All error
46375          * handling sites will process pending finalizers once error handling
46376          * is complete and we're ready for the side effects.  Does not prevent
46377          * refzero freeing or mark-and-sweep during error handling.
46378          *
46379          * NOTE: when we come here some calling code may have used DECREF
46380          * NORZ macros without an explicit DUK_REFZERO_CHECK_xxx() call.
46381          * We don't want to do it here because it would just check for
46382          * pending finalizers and we prevent that explicitly.  Instead,
46383          * the error catcher will run the finalizers once error handling
46384          * is complete.
46385          */
46386
46387         DUK_ASSERT_LJSTATE_SET(thr->heap);
46388
46389         thr->heap->pf_prevent_count++;
46390         DUK_ASSERT(thr->heap->pf_prevent_count != 0);  /* Wrap. */
46391
46392 #if defined(DUK_USE_ASSERTIONS)
46393         /* XXX: set this immediately when longjmp state is set */
46394         DUK_ASSERT(thr->heap->error_not_allowed == 0);  /* Detect error within critical section. */
46395         thr->heap->error_not_allowed = 1;
46396 #endif
46397
46398         DUK_DD(DUK_DDPRINT("about to longjmp, pf_prevent_count=%ld", (long) thr->heap->pf_prevent_count));
46399
46400         /* If we don't have a jmpbuf_ptr, there is little we can do except
46401          * cause a fatal error.  The caller's expectation is that we never
46402          * return.
46403          */
46404         if (!thr->heap->lj.jmpbuf_ptr) {
46405                 DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
46406                                  (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
46407                                  &thr->heap->lj.value1, &thr->heap->lj.value2));
46408
46409 #if defined(DUK_USE_PREFER_SIZE)
46410                 duk__uncaught_minimal(thr);
46411 #else
46412                 duk__uncaught_error_aware(thr);
46413 #endif
46414                 DUK_UNREACHABLE();
46415         }
46416
46417 #if defined(DUK_USE_CPP_EXCEPTIONS)
46418         throw duk_internal_exception();  /* dummy */
46419 #else
46420         DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
46421 #endif
46422
46423         DUK_UNREACHABLE();
46424 }
46425 #line 1 "duk_error_misc.c"
46426 /*
46427  *  Error helpers
46428  */
46429
46430 /* #include duk_internal.h -> already included */
46431
46432 /*
46433  *  Helper to walk the thread chain and see if there is an active error
46434  *  catcher.  Protected calls or finally blocks aren't considered catching.
46435  */
46436
46437 #if defined(DUK_USE_DEBUGGER_SUPPORT)
46438 DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
46439         /* As noted above, a protected API call won't be counted as a
46440          * catcher.  This is usually convenient, e.g. in the case of a top-
46441          * level duk_pcall(), but may not always be desirable.  Perhaps add
46442          * an argument to treat them as catchers?
46443          */
46444
46445         duk_activation *act;
46446         duk_catcher *cat;
46447
46448         DUK_ASSERT(thr != NULL);
46449
46450         for (; thr != NULL; thr = thr->resumer) {
46451                 for (act = thr->callstack_curr; act != NULL; act = act->parent) {
46452                         for (cat = act->cat; cat != NULL; cat = cat->parent) {
46453                                 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
46454                                         return 1;  /* all we need to know */
46455                                 }
46456                         }
46457                 }
46458         }
46459         return 0;
46460 }
46461 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
46462
46463 /*
46464  *  Get prototype object for an integer error code.
46465  */
46466
46467 DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) {
46468         switch (code) {
46469         case DUK_ERR_EVAL_ERROR:
46470                 return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE];
46471         case DUK_ERR_RANGE_ERROR:
46472                 return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE];
46473         case DUK_ERR_REFERENCE_ERROR:
46474                 return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE];
46475         case DUK_ERR_SYNTAX_ERROR:
46476                 return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE];
46477         case DUK_ERR_TYPE_ERROR:
46478                 return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
46479         case DUK_ERR_URI_ERROR:
46480                 return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
46481         case DUK_ERR_ERROR:
46482         default:
46483                 return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
46484         }
46485 }
46486
46487 /*
46488  *  Helper for debugger throw notify and pause-on-uncaught integration.
46489  */
46490
46491 #if defined(DUK_USE_DEBUGGER_SUPPORT)
46492 DUK_INTERNAL void duk_err_check_debugger_integration(duk_hthread *thr) {
46493         duk_bool_t uncaught;
46494         duk_tval *tv_obj;
46495
46496         /* If something is thrown with the debugger attached and nobody will
46497          * catch it, execution is paused before the longjmp, turning over
46498          * control to the debug client.  This allows local state to be examined
46499          * before the stack is unwound.  Errors are not intercepted when debug
46500          * message loop is active (e.g. for Eval).
46501          */
46502
46503         DUK_ASSERT(thr != NULL);
46504         DUK_ASSERT(thr->heap != NULL);
46505
46506         /* XXX: Allow customizing the pause and notify behavior at runtime
46507          * using debugger runtime flags.  For now the behavior is fixed using
46508          * config options.
46509          */
46510
46511         if (!duk_debug_is_attached(thr->heap) ||
46512             thr->heap->dbg_processing ||
46513             thr->heap->lj.type != DUK_LJ_TYPE_THROW ||
46514             thr->heap->creating_error) {
46515                 DUK_D(DUK_DPRINT("skip debugger error integration; not attached, debugger processing, not THROW, or error thrown while creating error"));
46516                 return;
46517         }
46518
46519         /* Don't intercept a DoubleError, we may have caused the initial double
46520          * fault and attempting to intercept it will cause us to be called
46521          * recursively and exhaust the C stack.  (This should no longer happen
46522          * for the initial throw because DoubleError path doesn't do a debugger
46523          * integration check, but it might happen for rethrows.)
46524          */
46525         tv_obj = &thr->heap->lj.value1;
46526         if (DUK_TVAL_IS_OBJECT(tv_obj) && DUK_TVAL_GET_OBJECT(tv_obj) == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
46527                 DUK_D(DUK_DPRINT("built-in DoubleError instance (re)thrown, not intercepting"));
46528                 return;
46529         }
46530
46531         uncaught = !duk__have_active_catcher(thr);
46532
46533         /* Debugger code expects the value at stack top.  This also serves
46534          * as a backup: we need to store/restore the longjmp state because
46535          * when the debugger is paused Eval commands may be executed and
46536          * they can arbitrarily clobber the longjmp state.
46537          */
46538         duk_push_tval(thr, tv_obj);
46539
46540         /* Store and reset longjmp state. */
46541         DUK_ASSERT_LJSTATE_SET(thr->heap);
46542         DUK_TVAL_DECREF_NORZ(thr, tv_obj);
46543         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));  /* Always for THROW type. */
46544         DUK_TVAL_SET_UNDEFINED(tv_obj);
46545         thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
46546         DUK_ASSERT_LJSTATE_UNSET(thr->heap);
46547
46548 #if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
46549         /* Report it to the debug client */
46550         DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
46551         duk_debug_send_throw(thr, uncaught);
46552 #endif
46553
46554         if (uncaught) {
46555                 if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_UNCAUGHT_ERROR) {
46556                         DUK_D(DUK_DPRINT("PAUSE TRIGGERED by uncaught error"));
46557                         duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
46558                 }
46559         } else {
46560                 if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_CAUGHT_ERROR) {
46561                         DUK_D(DUK_DPRINT("PAUSE TRIGGERED by caught error"));
46562                         duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
46563                 }
46564         }
46565
46566         /* Restore longjmp state. */
46567         DUK_ASSERT_LJSTATE_UNSET(thr->heap);
46568         thr->heap->lj.type = DUK_LJ_TYPE_THROW;
46569         tv_obj = DUK_GET_TVAL_NEGIDX(thr, -1);
46570         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
46571         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
46572         DUK_TVAL_SET_TVAL(&thr->heap->lj.value1, tv_obj);
46573         DUK_TVAL_INCREF(thr, tv_obj);
46574         DUK_ASSERT_LJSTATE_SET(thr->heap);
46575
46576         duk_pop(thr);
46577 }
46578 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
46579
46580 /*
46581  *  Helpers for setting up heap longjmp state.
46582  */
46583
46584 DUK_INTERNAL void duk_err_setup_ljstate1(duk_hthread *thr, duk_small_uint_t lj_type, duk_tval *tv_val) {
46585         duk_heap *heap;
46586
46587         DUK_ASSERT(thr != NULL);
46588         heap = thr->heap;
46589         DUK_ASSERT(heap != NULL);
46590         DUK_ASSERT(tv_val != NULL);
46591
46592         DUK_ASSERT_LJSTATE_UNSET(heap);
46593
46594         heap->lj.type = lj_type;
46595         DUK_TVAL_SET_TVAL(&heap->lj.value1, tv_val);
46596         DUK_TVAL_INCREF(thr, tv_val);
46597
46598         DUK_ASSERT_LJSTATE_SET(heap);
46599 }
46600 #line 1 "duk_error_throw.c"
46601 /*
46602  *  Create and throw an ECMAScript error object based on a code and a message.
46603  *
46604  *  Used when we throw errors internally.  ECMAScript generated error objects
46605  *  are created by ECMAScript code, and the throwing is handled by the bytecode
46606  *  executor.
46607  */
46608
46609 /* #include duk_internal.h -> already included */
46610
46611 /*
46612  *  Create and throw an error (originating from Duktape internally)
46613  *
46614  *  Push an error object on top of the stack, possibly throw augmenting
46615  *  the error, and finally longjmp.
46616  *
46617  *  If an error occurs while we're dealing with the current error, we might
46618  *  enter an infinite recursion loop.  This is prevented by detecting a
46619  *  "double fault" through the heap->creating_error flag; the recursion
46620  *  then stops at the second level.
46621  */
46622
46623 #if defined(DUK_USE_VERBOSE_ERRORS)
46624 DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) {
46625 #else
46626 DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
46627 #endif
46628 #if defined(DUK_USE_VERBOSE_ERRORS)
46629         DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
46630                            (long) code, (const char *) msg,
46631                            (const char *) filename, (long) line));
46632 #else
46633         DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code));
46634 #endif
46635
46636         DUK_ASSERT(thr != NULL);
46637
46638         /* Even though nested call is possible because we throw an error when
46639          * trying to create an error, the potential errors must happen before
46640          * the longjmp state is configured.
46641          */
46642         DUK_ASSERT_LJSTATE_UNSET(thr->heap);
46643
46644         /* Sync so that augmentation sees up-to-date activations, NULL
46645          * thr->ptr_curr_pc so that it's not used if side effects occur
46646          * in augmentation or longjmp handling.
46647          */
46648         duk_hthread_sync_and_null_currpc(thr);
46649
46650         /*
46651          *  Create and push an error object onto the top of stack.
46652          *  The error is potentially augmented before throwing.
46653          *
46654          *  If a "double error" occurs, use a fixed error instance
46655          *  to avoid further trouble.
46656          */
46657
46658         if (thr->heap->creating_error) {
46659                 duk_tval tv_val;
46660                 duk_hobject *h_err;
46661
46662                 thr->heap->creating_error = 0;
46663
46664                 h_err = thr->builtins[DUK_BIDX_DOUBLE_ERROR];
46665                 if (h_err != NULL) {
46666                         DUK_D(DUK_DPRINT("double fault detected -> use built-in fixed 'double error' instance"));
46667                         DUK_TVAL_SET_OBJECT(&tv_val, h_err);
46668                 } else {
46669                         DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
46670                                          "-> use the error code as a number"));
46671                         DUK_TVAL_SET_I32(&tv_val, (duk_int32_t) code);
46672                 }
46673
46674                 duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, &tv_val);
46675
46676                 /* No augmentation to avoid any allocations or side effects. */
46677         } else {
46678                 /* Prevent infinite recursion.  Extra call stack and C
46679                  * recursion headroom (see GH-191) is added for augmentation.
46680                  * That is now signalled by heap->augmenting error and taken
46681                  * into account in call handling without an explicit limit bump.
46682                  */
46683                 thr->heap->creating_error = 1;
46684
46685                 duk_require_stack(thr, 1);
46686
46687                 /* XXX: usually unnecessary '%s' formatting here, but cannot
46688                  * use 'msg' as a format string directly.
46689                  */
46690 #if defined(DUK_USE_VERBOSE_ERRORS)
46691                 duk_push_error_object_raw(thr,
46692                                           code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
46693                                           filename,
46694                                           line,
46695                                           "%s",
46696                                           (const char *) msg);
46697 #else
46698                 duk_push_error_object_raw(thr,
46699                                           code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
46700                                           NULL,
46701                                           0,
46702                                           NULL);
46703 #endif
46704
46705                 /* Note that an alloc error may happen during error augmentation.
46706                  * This may happen both when the original error is an alloc error
46707                  * and when it's something else.  Because any error in augmentation
46708                  * must be handled correctly anyway, there's no special check for
46709                  * avoiding it for alloc errors (this differs from Duktape 1.x).
46710                  */
46711 #if defined(DUK_USE_AUGMENT_ERROR_THROW)
46712                 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
46713                                      (duk_tval *) duk_get_tval(thr, -1)));
46714                 duk_err_augment_error_throw(thr);
46715 #endif
46716
46717                 duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
46718                 thr->heap->creating_error = 0;
46719
46720                 /* Error is now created and we assume no errors can occur any
46721                  * more.  Check for debugger Throw integration only when the
46722                  * error is complete.  If we enter debugger message loop,
46723                  * creating_error must be 0 so that errors can be thrown in
46724                  * the paused state, e.g. in Eval commands.
46725                  */
46726 #if defined(DUK_USE_DEBUGGER_SUPPORT)
46727                 duk_err_check_debugger_integration(thr);
46728 #endif
46729         }
46730
46731         /*
46732          *  Finally, longjmp
46733          */
46734
46735         DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
46736                              (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2));
46737
46738         duk_err_longjmp(thr);
46739         DUK_UNREACHABLE();
46740 }
46741
46742 /*
46743  *  Helper for C function call negative return values.
46744  */
46745
46746 DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
46747         DUK_ASSERT(thr != NULL);
46748         DUK_ASSERT(rc < 0);
46749
46750         /*
46751          *  The __FILE__ and __LINE__ information is intentionally not used in the
46752          *  creation of the error object, as it isn't useful in the tracedata.  The
46753          *  tracedata still contains the function which returned the negative return
46754          *  code, and having the file/line of this function isn't very useful.
46755          *
46756          *  The error messages for DUK_RET_xxx shorthand are intentionally very
46757          *  minimal: they're only really useful for low memory targets.
46758          */
46759
46760         duk_error_raw(thr, -rc, NULL, 0, "error (rc %ld)", (long) rc);
46761         DUK_WO_NORETURN(return;);
46762 }
46763 #line 1 "duk_hbuffer_alloc.c"
46764 /*
46765  *  duk_hbuffer allocation and freeing.
46766  */
46767
46768 /* #include duk_internal.h -> already included */
46769
46770 /* Allocate a new duk_hbuffer of a certain type and return a pointer to it
46771  * (NULL on error).  Write buffer data pointer to 'out_bufdata' (only if
46772  * allocation successful).
46773  */
46774 DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
46775         duk_hbuffer *res = NULL;
46776         duk_size_t header_size;
46777         duk_size_t alloc_size;
46778
46779         DUK_ASSERT(heap != NULL);
46780         DUK_ASSERT(out_bufdata != NULL);
46781
46782         DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));
46783
46784         /* Size sanity check.  Should not be necessary because caller is
46785          * required to check this, but we don't want to cause a segfault
46786          * if the size wraps either in duk_size_t computation or when
46787          * storing the size in a 16-bit field.
46788          */
46789         if (size > DUK_HBUFFER_MAX_BYTELEN) {
46790                 DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
46791                 return NULL;  /* no need to write 'out_bufdata' */
46792         }
46793
46794         if (flags & DUK_BUF_FLAG_EXTERNAL) {
46795                 header_size = sizeof(duk_hbuffer_external);
46796                 alloc_size = sizeof(duk_hbuffer_external);
46797         } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
46798                 header_size = sizeof(duk_hbuffer_dynamic);
46799                 alloc_size = sizeof(duk_hbuffer_dynamic);
46800         } else {
46801                 header_size = sizeof(duk_hbuffer_fixed);
46802                 alloc_size = sizeof(duk_hbuffer_fixed) + size;
46803                 DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed));  /* no wrapping */
46804         }
46805
46806         res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
46807         if (DUK_UNLIKELY(res == NULL)) {
46808                 goto alloc_error;
46809         }
46810
46811         /* zero everything unless requested not to do so */
46812 #if defined(DUK_USE_ZERO_BUFFER_DATA)
46813         duk_memzero((void *) res,
46814                     (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
46815 #else
46816         duk_memzero((void *) res, header_size);
46817 #endif
46818
46819         if (flags & DUK_BUF_FLAG_EXTERNAL) {
46820                 duk_hbuffer_external *h;
46821                 h = (duk_hbuffer_external *) res;
46822                 DUK_UNREF(h);
46823                 *out_bufdata = NULL;
46824 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
46825 #if defined(DUK_USE_HEAPPTR16)
46826 /* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
46827 #else
46828                 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
46829 #endif
46830 #endif
46831                 DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
46832         } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
46833                 duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
46834                 void *ptr;
46835
46836                 if (size > 0) {
46837                         DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));  /* alloc external with size zero */
46838                         DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
46839 #if defined(DUK_USE_ZERO_BUFFER_DATA)
46840                         ptr = DUK_ALLOC_ZEROED(heap, size);
46841 #else
46842                         ptr = DUK_ALLOC(heap, size);
46843 #endif
46844                         if (DUK_UNLIKELY(ptr == NULL)) {
46845                                 /* Because size > 0, NULL check is correct */
46846                                 goto alloc_error;
46847                         }
46848                         *out_bufdata = ptr;
46849
46850                         DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
46851                 } else {
46852                         *out_bufdata = NULL;
46853 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
46854 #if defined(DUK_USE_HEAPPTR16)
46855 /* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
46856 #else
46857                         DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
46858 #endif
46859 #endif
46860                         DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
46861                 }
46862         } else {
46863                 *out_bufdata = (void *) ((duk_hbuffer_fixed *) (void *) res + 1);
46864         }
46865
46866         DUK_HBUFFER_SET_SIZE(res, size);
46867
46868         DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
46869         if (flags & DUK_BUF_FLAG_DYNAMIC) {
46870                 DUK_HBUFFER_SET_DYNAMIC(res);
46871                 if (flags & DUK_BUF_FLAG_EXTERNAL) {
46872                         DUK_HBUFFER_SET_EXTERNAL(res);
46873                 }
46874         } else {
46875                 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
46876         }
46877         DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
46878
46879         DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
46880         return res;
46881
46882  alloc_error:
46883         DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
46884
46885         DUK_FREE(heap, res);
46886         return NULL;  /* no need to write 'out_bufdata' */
46887 }
46888
46889 /* For indirect allocs. */
46890
46891 DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
46892         duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud;
46893         DUK_UNREF(heap);
46894         return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
46895 }
46896 #line 1 "duk_hbuffer_ops.c"
46897 /*
46898  *  duk_hbuffer operations such as resizing and inserting/appending data to
46899  *  a dynamic buffer.
46900  */
46901
46902 /* #include duk_internal.h -> already included */
46903
46904 /*
46905  *  Resizing
46906  */
46907
46908 DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) {
46909         void *res;
46910         duk_size_t prev_size;
46911
46912         DUK_ASSERT(thr != NULL);
46913         DUK_ASSERT(buf != NULL);
46914         DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
46915         DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
46916
46917         /*
46918          *  Maximum size check
46919          */
46920
46921         if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
46922                 DUK_ERROR_RANGE(thr, "buffer too long");
46923                 DUK_WO_NORETURN(return;);
46924         }
46925
46926         /*
46927          *  Note: use indirect realloc variant just in case mark-and-sweep
46928          *  (finalizers) might resize this same buffer during garbage
46929          *  collection.
46930          */
46931
46932         res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size);
46933         if (DUK_LIKELY(res != NULL || new_size == 0)) {
46934                 /* 'res' may be NULL if new allocation size is 0. */
46935
46936                 DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld",
46937                                      (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf),
46938                                      (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf),
46939                                      (void *) res,
46940                                      (long) new_size));
46941
46942                 /*
46943                  *  The entire allocated buffer area, regardless of actual used
46944                  *  size, is kept zeroed in resizes for simplicity.  If the buffer
46945                  *  is grown, zero the new part.
46946                  */
46947
46948                 prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf);
46949                 if (new_size > prev_size) {
46950                         DUK_ASSERT(new_size - prev_size > 0);
46951 #if defined(DUK_USE_ZERO_BUFFER_DATA)
46952                         duk_memzero((void *) ((char *) res + prev_size),
46953                                     (duk_size_t) (new_size - prev_size));
46954 #endif
46955                 }
46956
46957                 DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size);
46958                 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
46959         } else {
46960                 DUK_ERROR_ALLOC_FAILED(thr);
46961                 DUK_WO_NORETURN(return;);
46962         }
46963
46964         DUK_ASSERT(res != NULL || new_size == 0);
46965 }
46966
46967 DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
46968         DUK_ASSERT(thr != NULL);
46969         DUK_ASSERT(buf != NULL);
46970         DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
46971         DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
46972
46973         duk_hbuffer_resize(thr, buf, 0);
46974 }
46975 /* #include duk_internal.h -> already included */
46976 #line 2 "duk_hbufobj_misc.c"
46977
46978 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
46979 DUK_INTERNAL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len) {
46980         duk_uint_t buf_size;
46981         duk_uint_t buf_avail;
46982
46983         DUK_ASSERT(h_bufobj != NULL);
46984         DUK_ASSERT(h_bufobj->buf != NULL);
46985
46986         buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf);
46987         if (h_bufobj->offset > buf_size) {
46988                 /* Slice starting point is beyond current length. */
46989                 return 0;
46990         }
46991         buf_avail = buf_size - h_bufobj->offset;
46992
46993         return buf_avail >= len ? len : buf_avail;
46994 }
46995 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
46996 #line 1 "duk_heap_alloc.c"
46997 /*
46998  *  duk_heap allocation and freeing.
46999  */
47000
47001 /* #include duk_internal.h -> already included */
47002
47003 #if defined(DUK_USE_ROM_STRINGS)
47004 /* Fixed seed value used with ROM strings. */
47005 #define DUK__FIXED_HASH_SEED       0xabcd1234
47006 #endif
47007
47008 /*
47009  *  Free a heap object.
47010  *
47011  *  Free heap object and its internal (non-heap) pointers.  Assumes that
47012  *  caller has removed the object from heap allocated list or the string
47013  *  intern table, and any weak references (which strings may have) have
47014  *  been already dealt with.
47015  */
47016
47017 DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) {
47018         DUK_ASSERT(heap != NULL);
47019         DUK_ASSERT(h != NULL);
47020
47021         DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
47022
47023         if (DUK_HOBJECT_IS_COMPFUNC(h)) {
47024                 duk_hcompfunc *f = (duk_hcompfunc *) h;
47025                 DUK_UNREF(f);
47026                 /* Currently nothing to free; 'data' is a heap object */
47027         } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
47028                 duk_hnatfunc *f = (duk_hnatfunc *) h;
47029                 DUK_UNREF(f);
47030                 /* Currently nothing to free */
47031         } else if (DUK_HOBJECT_IS_THREAD(h)) {
47032                 duk_hthread *t = (duk_hthread *) h;
47033                 duk_activation *act;
47034
47035                 DUK_FREE(heap, t->valstack);
47036
47037                 /* Don't free h->resumer because it exists in the heap.
47038                  * Callstack entries also contain function pointers which
47039                  * are not freed for the same reason.  They are decref
47040                  * finalized and the targets are freed if necessary based
47041                  * on their refcount (or reachability).
47042                  */
47043                 for (act = t->callstack_curr; act != NULL;) {
47044                         duk_activation *act_next;
47045                         duk_catcher *cat;
47046
47047                         for (cat = act->cat; cat != NULL;) {
47048                                 duk_catcher *cat_next;
47049
47050                                 cat_next = cat->parent;
47051                                 DUK_FREE(heap, (void *) cat);
47052                                 cat = cat_next;
47053                         }
47054
47055                         act_next = act->parent;
47056                         DUK_FREE(heap, (void *) act);
47057                         act = act_next;
47058                 }
47059
47060                 /* XXX: with 'caller' property the callstack would need
47061                  * to be unwound to update the 'caller' properties of
47062                  * functions in the callstack.
47063                  */
47064         } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
47065                 duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
47066
47067                 DUK_FREE(heap, f->args);
47068         }
47069
47070         DUK_FREE(heap, (void *) h);
47071 }
47072
47073 DUK_INTERNAL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h) {
47074         DUK_ASSERT(heap != NULL);
47075         DUK_ASSERT(h != NULL);
47076
47077         if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) {
47078                 duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
47079                 DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
47080                 DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g));
47081         }
47082         DUK_FREE(heap, (void *) h);
47083 }
47084
47085 DUK_INTERNAL void duk_free_hstring(duk_heap *heap, duk_hstring *h) {
47086         DUK_ASSERT(heap != NULL);
47087         DUK_ASSERT(h != NULL);
47088
47089         DUK_UNREF(heap);
47090         DUK_UNREF(h);
47091
47092 #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
47093         if (DUK_HSTRING_HAS_EXTDATA(h)) {
47094                 DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
47095                                      h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)));
47096                 DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
47097         }
47098 #endif
47099         DUK_FREE(heap, (void *) h);
47100 }
47101
47102 DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
47103         DUK_ASSERT(heap);
47104         DUK_ASSERT(hdr);
47105
47106         DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
47107
47108         switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
47109         case DUK_HTYPE_STRING:
47110                 duk_free_hstring(heap, (duk_hstring *) hdr);
47111                 break;
47112         case DUK_HTYPE_OBJECT:
47113                 duk_free_hobject(heap, (duk_hobject *) hdr);
47114                 break;
47115         default:
47116                 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_BUFFER);
47117                 duk_free_hbuffer(heap, (duk_hbuffer *) hdr);
47118         }
47119
47120 }
47121
47122 /*
47123  *  Free the heap.
47124  *
47125  *  Frees heap-related non-heap-tracked allocations such as the
47126  *  string intern table; then frees the heap allocated objects;
47127  *  and finally frees the heap structure itself.  Reference counts
47128  *  and GC markers are ignored (and not updated) in this process,
47129  *  and finalizers won't be called.
47130  *
47131  *  The heap pointer and heap object pointers must not be used
47132  *  after this call.
47133  */
47134
47135 #if defined(DUK_USE_CACHE_ACTIVATION)
47136 DUK_LOCAL duk_size_t duk__heap_free_activation_freelist(duk_heap *heap) {
47137         duk_activation *act;
47138         duk_activation *act_next;
47139         duk_size_t count_act = 0;
47140
47141         for (act = heap->activation_free; act != NULL;) {
47142                 act_next = act->parent;
47143                 DUK_FREE(heap, (void *) act);
47144                 act = act_next;
47145 #if defined(DUK_USE_DEBUG)
47146                 count_act++;
47147 #endif
47148         }
47149         heap->activation_free = NULL;  /* needed when called from mark-and-sweep */
47150         return count_act;
47151 }
47152 #endif  /* DUK_USE_CACHE_ACTIVATION */
47153
47154 #if defined(DUK_USE_CACHE_CATCHER)
47155 DUK_LOCAL duk_size_t duk__heap_free_catcher_freelist(duk_heap *heap) {
47156         duk_catcher *cat;
47157         duk_catcher *cat_next;
47158         duk_size_t count_cat = 0;
47159
47160         for (cat = heap->catcher_free; cat != NULL;) {
47161                 cat_next = cat->parent;
47162                 DUK_FREE(heap, (void *) cat);
47163                 cat = cat_next;
47164 #if defined(DUK_USE_DEBUG)
47165                 count_cat++;
47166 #endif
47167         }
47168         heap->catcher_free = NULL;  /* needed when called from mark-and-sweep */
47169
47170         return count_cat;
47171 }
47172 #endif  /* DUK_USE_CACHE_CATCHER */
47173
47174 DUK_INTERNAL void duk_heap_free_freelists(duk_heap *heap) {
47175         duk_size_t count_act = 0;
47176         duk_size_t count_cat = 0;
47177
47178 #if defined(DUK_USE_CACHE_ACTIVATION)
47179         count_act = duk__heap_free_activation_freelist(heap);
47180 #endif
47181 #if defined(DUK_USE_CACHE_CATCHER)
47182         count_cat = duk__heap_free_catcher_freelist(heap);
47183 #endif
47184         DUK_UNREF(heap);
47185         DUK_UNREF(count_act);
47186         DUK_UNREF(count_cat);
47187
47188         DUK_D(DUK_DPRINT("freed %ld activation freelist entries, %ld catcher freelist entries",
47189                          (long) count_act, (long) count_cat));
47190 }
47191
47192 DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
47193         duk_heaphdr *curr;
47194         duk_heaphdr *next;
47195
47196         curr = heap->heap_allocated;
47197         while (curr) {
47198                 /* We don't log or warn about freeing zero refcount objects
47199                  * because they may happen with finalizer processing.
47200                  */
47201
47202                 DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
47203                                      (duk_heaphdr *) curr));
47204                 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
47205                 duk_heap_free_heaphdr_raw(heap, curr);
47206                 curr = next;
47207         }
47208 }
47209
47210 #if defined(DUK_USE_FINALIZER_SUPPORT)
47211 DUK_LOCAL void duk__free_finalize_list(duk_heap *heap) {
47212         duk_heaphdr *curr;
47213         duk_heaphdr *next;
47214
47215         curr = heap->finalize_list;
47216         while (curr) {
47217                 DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
47218                                      (duk_heaphdr *) curr));
47219                 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
47220                 duk_heap_free_heaphdr_raw(heap, curr);
47221                 curr = next;
47222         }
47223 }
47224 #endif  /* DUK_USE_FINALIZER_SUPPORT */
47225
47226 DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
47227         /* strings are only tracked by stringtable */
47228         duk_heap_strtable_free(heap);
47229 }
47230
47231 #if defined(DUK_USE_FINALIZER_SUPPORT)
47232 DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
47233         duk_heaphdr *curr;
47234         duk_uint_t round_no;
47235         duk_size_t count_all;
47236         duk_size_t count_finalized;
47237         duk_size_t curr_limit;
47238
47239         DUK_ASSERT(heap != NULL);
47240
47241 #if defined(DUK_USE_REFERENCE_COUNTING)
47242         DUK_ASSERT(heap->refzero_list == NULL);  /* refzero not running -> must be empty */
47243 #endif
47244         DUK_ASSERT(heap->finalize_list == NULL);  /* mark-and-sweep last pass */
47245
47246         if (heap->heap_thread == NULL) {
47247                 /* May happen when heap allocation fails right off.  There
47248                  * cannot be any finalizable objects in this case.
47249                  */
47250                 DUK_D(DUK_DPRINT("no heap_thread in heap destruct, assume no finalizable objects"));
47251                 return;
47252         }
47253
47254         /* Prevent finalize_list processing and mark-and-sweep entirely.
47255          * Setting ms_running = 1 also prevents refzero handling from moving
47256          * objects away from the heap_allocated list (the flag name is a bit
47257          * misleading here).
47258          */
47259         DUK_ASSERT(heap->pf_prevent_count == 0);
47260         heap->pf_prevent_count = 1;
47261         DUK_ASSERT(heap->ms_running == 0);
47262         heap->ms_running = 1;
47263         DUK_ASSERT(heap->ms_prevent_count == 0);
47264         heap->ms_prevent_count = 1;  /* Bump, because mark-and-sweep assumes it's bumped when ms_running is set. */
47265
47266         curr_limit = 0;  /* suppress warning, not used */
47267         for (round_no = 0; ; round_no++) {
47268                 curr = heap->heap_allocated;
47269                 count_all = 0;
47270                 count_finalized = 0;
47271                 while (curr) {
47272                         count_all++;
47273                         if (DUK_HEAPHDR_IS_OBJECT(curr)) {
47274                                 /* Only objects in heap_allocated may have finalizers.  Check that
47275                                  * the object itself has a _Finalizer property (own or inherited)
47276                                  * so that we don't execute finalizers for e.g. Proxy objects.
47277                                  */
47278                                 DUK_ASSERT(curr != NULL);
47279
47280                                 if (DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) curr)) {
47281                                         if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
47282                                                 DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap));  /* maps to finalizer 2nd argument */
47283                                                 duk_heap_run_finalizer(heap, (duk_hobject *) curr);
47284                                                 count_finalized++;
47285                                         }
47286                                 }
47287                         }
47288                         curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
47289                 }
47290
47291                 /* Each round of finalizer execution may spawn new finalizable objects
47292                  * which is normal behavior for some applications.  Allow multiple
47293                  * rounds of finalization, but use a shrinking limit based on the
47294                  * first round to detect the case where a runaway finalizer creates
47295                  * an unbounded amount of new finalizable objects.  Finalizer rescue
47296                  * is not supported: the semantics are unclear because most of the
47297                  * objects being finalized here are already reachable.  The finalizer
47298                  * is given a boolean to indicate that rescue is not possible.
47299                  *
47300                  * See discussion in: https://github.com/svaarala/duktape/pull/473
47301                  */
47302
47303                 if (round_no == 0) {
47304                         /* Cannot wrap: each object is at least 8 bytes so count is
47305                          * at most 1/8 of that.
47306                          */
47307                         curr_limit = count_all * 2;
47308                 } else {
47309                         curr_limit = (curr_limit * 3) / 4;   /* Decrease by 25% every round */
47310                 }
47311                 DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld",
47312                                  (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit));
47313
47314                 if (count_finalized == 0) {
47315                         DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished"));
47316                         break;
47317                 }
47318                 if (count_finalized >= curr_limit) {
47319                         DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers"));
47320                         break;
47321                 }
47322         }
47323
47324         DUK_ASSERT(heap->ms_running == 1);
47325         heap->ms_running = 0;
47326         DUK_ASSERT(heap->pf_prevent_count == 1);
47327         heap->pf_prevent_count = 0;
47328 }
47329 #endif  /* DUK_USE_FINALIZER_SUPPORT */
47330
47331 DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
47332         DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
47333
47334 #if defined(DUK_USE_DEBUG)
47335         duk_heap_strtable_dump(heap);
47336 #endif
47337
47338 #if defined(DUK_USE_DEBUGGER_SUPPORT)
47339         /* Detach a debugger if attached (can be called multiple times)
47340          * safely.
47341          */
47342         /* XXX: Add a flag to reject an attempt to re-attach?  Otherwise
47343          * the detached callback may immediately reattach.
47344          */
47345         duk_debug_do_detach(heap);
47346 #endif
47347
47348         /* Execute finalizers before freeing the heap, even for reachable
47349          * objects.  This gives finalizers the chance to free any native
47350          * resources like file handles, allocations made outside Duktape,
47351          * etc.  This is quite tricky to get right, so that all finalizer
47352          * guarantees are honored.
47353          *
47354          * Run mark-and-sweep a few times just in case (unreachable object
47355          * finalizers run already here).  The last round must rescue objects
47356          * from the previous round without running any more finalizers.  This
47357          * ensures rescued objects get their FINALIZED flag cleared so that
47358          * their finalizer is called once more in forced finalization to
47359          * satisfy finalizer guarantees.  However, we don't want to run any
47360          * more finalizers because that'd required one more loop, and so on.
47361          *
47362          * XXX: this perhaps requires an execution time limit.
47363          */
47364         DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
47365         DUK_ASSERT(heap->pf_skip_finalizers == 0);
47366         DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
47367         duk_heap_mark_and_sweep(heap, 0);
47368         DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
47369         duk_heap_mark_and_sweep(heap, 0);
47370         DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
47371         heap->pf_skip_finalizers = 1;
47372         duk_heap_mark_and_sweep(heap, 0);  /* Skip finalizers; queue finalizable objects to heap_allocated. */
47373
47374         /* There are never objects in refzero_list at this point, or at any
47375          * point beyond a DECREF (even a DECREF_NORZ).  Since Duktape 2.1
47376          * refzero_list processing is side effect free, so it is always
47377          * processed to completion by a DECREF initially triggering a zero
47378          * refcount.
47379          */
47380 #if defined(DUK_USE_REFERENCE_COUNTING)
47381         DUK_ASSERT(heap->refzero_list == NULL);  /* Always processed to completion inline. */
47382 #endif
47383 #if defined(DUK_USE_FINALIZER_SUPPORT)
47384         DUK_ASSERT(heap->finalize_list == NULL);  /* Last mark-and-sweep with skip_finalizers. */
47385 #endif
47386
47387 #if defined(DUK_USE_FINALIZER_SUPPORT)
47388         DUK_D(DUK_DPRINT("run finalizers for remaining finalizable objects"));
47389         DUK_HEAP_SET_FINALIZER_NORESCUE(heap);  /* Rescue no longer supported. */
47390         duk__free_run_finalizers(heap);
47391 #endif  /* DUK_USE_FINALIZER_SUPPORT */
47392
47393         /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
47394          * are on the heap allocated list.
47395          */
47396
47397         DUK_D(DUK_DPRINT("freeing temporary freelists"));
47398         duk_heap_free_freelists(heap);
47399
47400         DUK_D(DUK_DPRINT("freeing heap_allocated of heap: %p", (void *) heap));
47401         duk__free_allocated(heap);
47402
47403 #if defined(DUK_USE_REFERENCE_COUNTING)
47404         DUK_ASSERT(heap->refzero_list == NULL);  /* Always processed to completion inline. */
47405 #endif
47406
47407 #if defined(DUK_USE_FINALIZER_SUPPORT)
47408         DUK_D(DUK_DPRINT("freeing finalize_list of heap: %p", (void *) heap));
47409         duk__free_finalize_list(heap);
47410 #endif
47411
47412         DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
47413         duk__free_stringtable(heap);
47414
47415         DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap));
47416         heap->free_func(heap->heap_udata, heap);
47417 }
47418
47419 /*
47420  *  Allocate a heap.
47421  *
47422  *  String table is initialized with built-in strings from genbuiltins.py,
47423  *  either by dynamically creating the strings or by referring to ROM strings.
47424  */
47425
47426 #if defined(DUK_USE_ROM_STRINGS)
47427 DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
47428 #if defined(DUK_USE_ASSERTIONS)
47429         duk_small_uint_t i;
47430 #endif
47431
47432         DUK_UNREF(heap);
47433
47434         /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted
47435          * so nothing to initialize for strs[].
47436          */
47437
47438 #if defined(DUK_USE_ASSERTIONS)
47439         for (i = 0; i < sizeof(duk_rom_strings_lookup) / sizeof(const duk_hstring *); i++) {
47440                 const duk_hstring *h;
47441                 duk_uint32_t hash;
47442
47443                 h = duk_rom_strings_lookup[i];
47444                 while (h != NULL) {
47445                         hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
47446                         DUK_DD(DUK_DDPRINT("duk_rom_strings_lookup[%d] -> hash 0x%08lx, computed 0x%08lx",
47447                                            (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
47448                         DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
47449
47450                         h = (const duk_hstring *) h->hdr.h_next;
47451                 }
47452         }
47453 #endif
47454         return 1;
47455 }
47456 #else  /* DUK_USE_ROM_STRINGS */
47457
47458 DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
47459         duk_bitdecoder_ctx bd_ctx;
47460         duk_bitdecoder_ctx *bd = &bd_ctx;  /* convenience */
47461         duk_small_uint_t i;
47462
47463         duk_memzero(&bd_ctx, sizeof(bd_ctx));
47464         bd->data = (const duk_uint8_t *) duk_strings_data;
47465         bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
47466
47467         for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
47468                 duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
47469                 duk_small_uint_t len;
47470                 duk_hstring *h;
47471
47472                 len = duk_bd_decode_bitpacked_string(bd, tmp);
47473
47474                 /* No need to length check string: it will never exceed even
47475                  * the 16-bit length maximum.
47476                  */
47477                 DUK_ASSERT(len <= 0xffffUL);
47478                 DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
47479                 h = duk_heap_strtable_intern(heap, tmp, len);
47480                 if (!h) {
47481                         goto failed;
47482                 }
47483                 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
47484
47485                 /* Special flags checks.  Since these strings are always
47486                  * reachable and a string cannot appear twice in the string
47487                  * table, there's no need to check/set these flags elsewhere.
47488                  * The 'internal' flag is set by string intern code.
47489                  */
47490                 if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
47491                         DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
47492                 }
47493                 if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
47494                         DUK_HSTRING_SET_RESERVED_WORD(h);
47495                         if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
47496                                 DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
47497                         }
47498                 }
47499
47500                 DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));
47501
47502                 /* XXX: The incref macro takes a thread pointer but doesn't
47503                  * use it right now.
47504                  */
47505                 DUK_HSTRING_INCREF(_never_referenced_, h);
47506
47507 #if defined(DUK_USE_HEAPPTR16)
47508                 heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
47509 #else
47510                 heap->strs[i] = h;
47511 #endif
47512         }
47513
47514         return 1;
47515
47516  failed:
47517         return 0;
47518 }
47519 #endif  /* DUK_USE_ROM_STRINGS */
47520
47521 DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
47522         duk_hthread *thr;
47523
47524         DUK_D(DUK_DPRINT("heap init: alloc heap thread"));
47525         thr = duk_hthread_alloc_unchecked(heap,
47526                                           DUK_HOBJECT_FLAG_EXTENSIBLE |
47527                                           DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
47528         if (thr == NULL) {
47529                 DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
47530                 return 0;
47531         }
47532         thr->state = DUK_HTHREAD_STATE_INACTIVE;
47533 #if defined(DUK_USE_ROM_STRINGS)
47534         /* No strs[] pointer. */
47535 #else  /* DUK_USE_ROM_STRINGS */
47536 #if defined(DUK_USE_HEAPPTR16)
47537         thr->strs16 = heap->strs16;
47538 #else
47539         thr->strs = heap->strs;
47540 #endif
47541 #endif  /* DUK_USE_ROM_STRINGS */
47542
47543         heap->heap_thread = thr;
47544         DUK_HTHREAD_INCREF(thr, thr);  /* Note: first argument not really used */
47545
47546         /* 'thr' is now reachable */
47547
47548         DUK_D(DUK_DPRINT("heap init: init heap thread stacks"));
47549         if (!duk_hthread_init_stacks(heap, thr)) {
47550                 return 0;
47551         }
47552
47553         /* XXX: this may now fail, and is not handled correctly */
47554         duk_hthread_create_builtin_objects(thr);
47555
47556         /* default prototype */
47557         DUK_HOBJECT_SET_PROTOTYPE_INIT_INCREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
47558
47559         return 1;
47560 }
47561
47562 #if defined(DUK_USE_DEBUG)
47563 #define DUK__DUMPSZ(t)  do { \
47564                 DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
47565         } while (0)
47566
47567 /* These is not 100% because format would need to be non-portable "long long".
47568  * Also print out as doubles to catch cases where the "long" type is not wide
47569  * enough; the limits will then not be printed accurately but the magnitude
47570  * will be correct.
47571  */
47572 #define DUK__DUMPLM_SIGNED_RAW(t,a,b)  do { \
47573                 DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
47574                                  (long) (a), (long) (b), \
47575                                  (double) (a), (double) (b))); \
47576         } while (0)
47577 #define DUK__DUMPLM_UNSIGNED_RAW(t,a,b)  do { \
47578                 DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
47579                                  (unsigned long) (a), (unsigned long) (b), \
47580                                  (double) (a), (double) (b))); \
47581         } while (0)
47582 #define DUK__DUMPLM_SIGNED(t)  do { \
47583                 DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
47584         } while (0)
47585 #define DUK__DUMPLM_UNSIGNED(t)  do { \
47586                 DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
47587         } while (0)
47588
47589 DUK_LOCAL void duk__dump_type_sizes(void) {
47590         DUK_D(DUK_DPRINT("sizeof()"));
47591
47592         /* basic platform types */
47593         DUK__DUMPSZ(char);
47594         DUK__DUMPSZ(short);
47595         DUK__DUMPSZ(int);
47596         DUK__DUMPSZ(long);
47597         DUK__DUMPSZ(double);
47598         DUK__DUMPSZ(void *);
47599         DUK__DUMPSZ(size_t);
47600
47601         /* basic types from duk_features.h */
47602         DUK__DUMPSZ(duk_uint8_t);
47603         DUK__DUMPSZ(duk_int8_t);
47604         DUK__DUMPSZ(duk_uint16_t);
47605         DUK__DUMPSZ(duk_int16_t);
47606         DUK__DUMPSZ(duk_uint32_t);
47607         DUK__DUMPSZ(duk_int32_t);
47608         DUK__DUMPSZ(duk_uint64_t);
47609         DUK__DUMPSZ(duk_int64_t);
47610         DUK__DUMPSZ(duk_uint_least8_t);
47611         DUK__DUMPSZ(duk_int_least8_t);
47612         DUK__DUMPSZ(duk_uint_least16_t);
47613         DUK__DUMPSZ(duk_int_least16_t);
47614         DUK__DUMPSZ(duk_uint_least32_t);
47615         DUK__DUMPSZ(duk_int_least32_t);
47616 #if defined(DUK_USE_64BIT_OPS)
47617         DUK__DUMPSZ(duk_uint_least64_t);
47618         DUK__DUMPSZ(duk_int_least64_t);
47619 #endif
47620         DUK__DUMPSZ(duk_uint_fast8_t);
47621         DUK__DUMPSZ(duk_int_fast8_t);
47622         DUK__DUMPSZ(duk_uint_fast16_t);
47623         DUK__DUMPSZ(duk_int_fast16_t);
47624         DUK__DUMPSZ(duk_uint_fast32_t);
47625         DUK__DUMPSZ(duk_int_fast32_t);
47626 #if defined(DUK_USE_64BIT_OPS)
47627         DUK__DUMPSZ(duk_uint_fast64_t);
47628         DUK__DUMPSZ(duk_int_fast64_t);
47629 #endif
47630         DUK__DUMPSZ(duk_uintptr_t);
47631         DUK__DUMPSZ(duk_intptr_t);
47632         DUK__DUMPSZ(duk_uintmax_t);
47633         DUK__DUMPSZ(duk_intmax_t);
47634         DUK__DUMPSZ(duk_double_t);
47635
47636         /* important chosen base types */
47637         DUK__DUMPSZ(duk_int_t);
47638         DUK__DUMPSZ(duk_uint_t);
47639         DUK__DUMPSZ(duk_int_fast_t);
47640         DUK__DUMPSZ(duk_uint_fast_t);
47641         DUK__DUMPSZ(duk_small_int_t);
47642         DUK__DUMPSZ(duk_small_uint_t);
47643         DUK__DUMPSZ(duk_small_int_fast_t);
47644         DUK__DUMPSZ(duk_small_uint_fast_t);
47645
47646         /* some derived types */
47647         DUK__DUMPSZ(duk_codepoint_t);
47648         DUK__DUMPSZ(duk_ucodepoint_t);
47649         DUK__DUMPSZ(duk_idx_t);
47650         DUK__DUMPSZ(duk_errcode_t);
47651         DUK__DUMPSZ(duk_uarridx_t);
47652
47653         /* tval */
47654         DUK__DUMPSZ(duk_double_union);
47655         DUK__DUMPSZ(duk_tval);
47656
47657         /* structs from duk_forwdecl.h */
47658         DUK__DUMPSZ(duk_jmpbuf);  /* just one 'int' for C++ exceptions */
47659         DUK__DUMPSZ(duk_heaphdr);
47660         DUK__DUMPSZ(duk_heaphdr_string);
47661         DUK__DUMPSZ(duk_hstring);
47662         DUK__DUMPSZ(duk_hstring_external);
47663         DUK__DUMPSZ(duk_hobject);
47664         DUK__DUMPSZ(duk_harray);
47665         DUK__DUMPSZ(duk_hcompfunc);
47666         DUK__DUMPSZ(duk_hnatfunc);
47667         DUK__DUMPSZ(duk_hdecenv);
47668         DUK__DUMPSZ(duk_hobjenv);
47669         DUK__DUMPSZ(duk_hthread);
47670 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
47671         DUK__DUMPSZ(duk_hbufobj);
47672 #endif
47673         DUK__DUMPSZ(duk_hproxy);
47674         DUK__DUMPSZ(duk_hbuffer);
47675         DUK__DUMPSZ(duk_hbuffer_fixed);
47676         DUK__DUMPSZ(duk_hbuffer_dynamic);
47677         DUK__DUMPSZ(duk_hbuffer_external);
47678         DUK__DUMPSZ(duk_propaccessor);
47679         DUK__DUMPSZ(duk_propvalue);
47680         DUK__DUMPSZ(duk_propdesc);
47681         DUK__DUMPSZ(duk_heap);
47682         DUK__DUMPSZ(duk_activation);
47683         DUK__DUMPSZ(duk_catcher);
47684         DUK__DUMPSZ(duk_strcache_entry);
47685         DUK__DUMPSZ(duk_litcache_entry);
47686         DUK__DUMPSZ(duk_ljstate);
47687         DUK__DUMPSZ(duk_fixedbuffer);
47688         DUK__DUMPSZ(duk_bitdecoder_ctx);
47689         DUK__DUMPSZ(duk_bitencoder_ctx);
47690         DUK__DUMPSZ(duk_token);
47691         DUK__DUMPSZ(duk_re_token);
47692         DUK__DUMPSZ(duk_lexer_point);
47693         DUK__DUMPSZ(duk_lexer_ctx);
47694         DUK__DUMPSZ(duk_compiler_instr);
47695         DUK__DUMPSZ(duk_compiler_func);
47696         DUK__DUMPSZ(duk_compiler_ctx);
47697         DUK__DUMPSZ(duk_re_matcher_ctx);
47698         DUK__DUMPSZ(duk_re_compiler_ctx);
47699 }
47700 DUK_LOCAL void duk__dump_type_limits(void) {
47701         DUK_D(DUK_DPRINT("limits"));
47702
47703         /* basic types */
47704         DUK__DUMPLM_SIGNED(INT8);
47705         DUK__DUMPLM_UNSIGNED(UINT8);
47706         DUK__DUMPLM_SIGNED(INT_FAST8);
47707         DUK__DUMPLM_UNSIGNED(UINT_FAST8);
47708         DUK__DUMPLM_SIGNED(INT_LEAST8);
47709         DUK__DUMPLM_UNSIGNED(UINT_LEAST8);
47710         DUK__DUMPLM_SIGNED(INT16);
47711         DUK__DUMPLM_UNSIGNED(UINT16);
47712         DUK__DUMPLM_SIGNED(INT_FAST16);
47713         DUK__DUMPLM_UNSIGNED(UINT_FAST16);
47714         DUK__DUMPLM_SIGNED(INT_LEAST16);
47715         DUK__DUMPLM_UNSIGNED(UINT_LEAST16);
47716         DUK__DUMPLM_SIGNED(INT32);
47717         DUK__DUMPLM_UNSIGNED(UINT32);
47718         DUK__DUMPLM_SIGNED(INT_FAST32);
47719         DUK__DUMPLM_UNSIGNED(UINT_FAST32);
47720         DUK__DUMPLM_SIGNED(INT_LEAST32);
47721         DUK__DUMPLM_UNSIGNED(UINT_LEAST32);
47722 #if defined(DUK_USE_64BIT_OPS)
47723         DUK__DUMPLM_SIGNED(INT64);
47724         DUK__DUMPLM_UNSIGNED(UINT64);
47725         DUK__DUMPLM_SIGNED(INT_FAST64);
47726         DUK__DUMPLM_UNSIGNED(UINT_FAST64);
47727         DUK__DUMPLM_SIGNED(INT_LEAST64);
47728         DUK__DUMPLM_UNSIGNED(UINT_LEAST64);
47729 #endif
47730         DUK__DUMPLM_SIGNED(INTPTR);
47731         DUK__DUMPLM_UNSIGNED(UINTPTR);
47732         DUK__DUMPLM_SIGNED(INTMAX);
47733         DUK__DUMPLM_UNSIGNED(UINTMAX);
47734
47735         /* derived types */
47736         DUK__DUMPLM_SIGNED(INT);
47737         DUK__DUMPLM_UNSIGNED(UINT);
47738         DUK__DUMPLM_SIGNED(INT_FAST);
47739         DUK__DUMPLM_UNSIGNED(UINT_FAST);
47740         DUK__DUMPLM_SIGNED(SMALL_INT);
47741         DUK__DUMPLM_UNSIGNED(SMALL_UINT);
47742         DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
47743         DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
47744 }
47745
47746 DUK_LOCAL void duk__dump_misc_options(void) {
47747         DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
47748         DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
47749         DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
47750         DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
47751         DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
47752         DUK_D(DUK_DPRINT("debug level: %ld", (long) DUK_USE_DEBUG_LEVEL));
47753 #if defined(DUK_USE_PACKED_TVAL)
47754         DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
47755 #else
47756         DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
47757 #endif
47758 #if defined(DUK_USE_VARIADIC_MACROS)
47759         DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes"));
47760 #else
47761         DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no"));
47762 #endif
47763 #if defined(DUK_USE_INTEGER_LE)
47764         DUK_D(DUK_DPRINT("integer endianness: little"));
47765 #elif defined(DUK_USE_INTEGER_ME)
47766         DUK_D(DUK_DPRINT("integer endianness: mixed"));
47767 #elif defined(DUK_USE_INTEGER_BE)
47768         DUK_D(DUK_DPRINT("integer endianness: big"));
47769 #else
47770         DUK_D(DUK_DPRINT("integer endianness: ???"));
47771 #endif
47772 #if defined(DUK_USE_DOUBLE_LE)
47773         DUK_D(DUK_DPRINT("IEEE double endianness: little"));
47774 #elif defined(DUK_USE_DOUBLE_ME)
47775         DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
47776 #elif defined(DUK_USE_DOUBLE_BE)
47777         DUK_D(DUK_DPRINT("IEEE double endianness: big"));
47778 #else
47779         DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
47780 #endif
47781 }
47782 #endif  /* DUK_USE_DEBUG */
47783
47784 DUK_INTERNAL
47785 duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
47786                          duk_realloc_function realloc_func,
47787                          duk_free_function free_func,
47788                          void *heap_udata,
47789                          duk_fatal_function fatal_func) {
47790         duk_heap *res = NULL;
47791         duk_uint32_t st_initsize;
47792
47793         DUK_D(DUK_DPRINT("allocate heap"));
47794
47795         /*
47796          *  Random config sanity asserts
47797          */
47798
47799         DUK_ASSERT(DUK_USE_STRTAB_MINSIZE >= 64);
47800
47801         DUK_ASSERT((DUK_HTYPE_STRING & 0x01U) == 0);
47802         DUK_ASSERT((DUK_HTYPE_BUFFER & 0x01U) == 0);
47803         DUK_ASSERT((DUK_HTYPE_OBJECT & 0x01U) == 1);  /* DUK_HEAPHDR_IS_OBJECT() relies ont his. */
47804
47805         /*
47806          *  Debug dump type sizes
47807          */
47808
47809 #if defined(DUK_USE_DEBUG)
47810         duk__dump_misc_options();
47811         duk__dump_type_sizes();
47812         duk__dump_type_limits();
47813 #endif
47814
47815         /*
47816          *  If selftests enabled, run them as early as possible.
47817          */
47818
47819 #if defined(DUK_USE_SELF_TESTS)
47820         DUK_D(DUK_DPRINT("run self tests"));
47821         if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) {
47822                 fatal_func(heap_udata, "self test(s) failed");
47823         }
47824         DUK_D(DUK_DPRINT("self tests passed"));
47825 #endif
47826
47827         /*
47828          *  Important assert-like checks that should be enabled even
47829          *  when assertions are otherwise not enabled.
47830          */
47831
47832 #if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE)
47833         /* Can't check sizeof() using preprocessor so explicit check.
47834          * This will be optimized away in practice; unfortunately a
47835          * warning is generated on some compilers as a result.
47836          */
47837 #if defined(DUK_USE_PACKED_TVAL)
47838         if (sizeof(duk_tval) != 8) {
47839 #else
47840         if (sizeof(duk_tval) != 16) {
47841 #endif
47842                 fatal_func(heap_udata, "sizeof(duk_tval) not 8 or 16, cannot use DUK_USE_EXEC_REGCONST_OPTIMIZE option");
47843         }
47844 #endif  /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
47845
47846         /*
47847          *  Computed values (e.g. INFINITY)
47848          */
47849
47850 #if defined(DUK_USE_COMPUTED_NAN)
47851         do {
47852                 /* Workaround for some exotic platforms where NAN is missing
47853                  * and the expression (0.0 / 0.0) does NOT result in a NaN.
47854                  * Such platforms use the global 'duk_computed_nan' which must
47855                  * be initialized at runtime.  Use 'volatile' to ensure that
47856                  * the compiler will actually do the computation and not try
47857                  * to do constant folding which might result in the original
47858                  * problem.
47859                  */
47860                 volatile double dbl1 = 0.0;
47861                 volatile double dbl2 = 0.0;
47862                 duk_computed_nan = dbl1 / dbl2;
47863         } while (0);
47864 #endif
47865
47866 #if defined(DUK_USE_COMPUTED_INFINITY)
47867         do {
47868                 /* Similar workaround for INFINITY. */
47869                 volatile double dbl1 = 1.0;
47870                 volatile double dbl2 = 0.0;
47871                 duk_computed_infinity = dbl1 / dbl2;
47872         } while (0);
47873 #endif
47874
47875         /*
47876          *  Allocate heap struct
47877          *
47878          *  Use a raw call, all macros expect the heap to be initialized
47879          */
47880
47881 #if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 1)
47882         goto failed;
47883 #endif
47884         DUK_D(DUK_DPRINT("alloc duk_heap object"));
47885         res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
47886         if (!res) {
47887                 goto failed;
47888         }
47889
47890         /*
47891          *  Zero the struct, and start initializing roughly in order
47892          */
47893
47894         duk_memzero(res, sizeof(*res));
47895 #if defined(DUK_USE_ASSERTIONS)
47896         res->heap_initializing = 1;
47897 #endif
47898
47899         /* explicit NULL inits */
47900 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
47901         res->heap_udata = NULL;
47902         res->heap_allocated = NULL;
47903 #if defined(DUK_USE_REFERENCE_COUNTING)
47904         res->refzero_list = NULL;
47905 #endif
47906 #if defined(DUK_USE_FINALIZER_SUPPORT)
47907         res->finalize_list = NULL;
47908 #if defined(DUK_USE_ASSERTIONS)
47909         res->currently_finalizing = NULL;
47910 #endif
47911 #endif
47912 #if defined(DUK_USE_CACHE_ACTIVATION)
47913         res->activation_free = NULL;
47914 #endif
47915 #if defined(DUK_USE_CACHE_CATCHER)
47916         res->catcher_free = NULL;
47917 #endif
47918         res->heap_thread = NULL;
47919         res->curr_thread = NULL;
47920         res->heap_object = NULL;
47921 #if defined(DUK_USE_STRTAB_PTRCOMP)
47922         res->strtable16 = NULL;
47923 #else
47924         res->strtable = NULL;
47925 #endif
47926 #if defined(DUK_USE_ROM_STRINGS)
47927         /* no res->strs[] */
47928 #else  /* DUK_USE_ROM_STRINGS */
47929 #if defined(DUK_USE_HEAPPTR16)
47930         /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
47931 #else
47932         {
47933                 duk_small_uint_t i;
47934                 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
47935                         res->strs[i] = NULL;
47936                 }
47937         }
47938 #endif
47939 #endif  /* DUK_USE_ROM_STRINGS */
47940 #if defined(DUK_USE_DEBUGGER_SUPPORT)
47941         res->dbg_read_cb = NULL;
47942         res->dbg_write_cb = NULL;
47943         res->dbg_peek_cb = NULL;
47944         res->dbg_read_flush_cb = NULL;
47945         res->dbg_write_flush_cb = NULL;
47946         res->dbg_request_cb = NULL;
47947         res->dbg_udata = NULL;
47948         res->dbg_pause_act = NULL;
47949 #endif
47950 #endif  /* DUK_USE_EXPLICIT_NULL_INIT */
47951
47952         res->alloc_func = alloc_func;
47953         res->realloc_func = realloc_func;
47954         res->free_func = free_func;
47955         res->heap_udata = heap_udata;
47956         res->fatal_func = fatal_func;
47957
47958         /* XXX: for now there's a pointer packing zero assumption, i.e.
47959          * NULL <=> compressed pointer 0.  If this is removed, may need
47960          * to precompute e.g. null16 here.
47961          */
47962
47963         /* res->ms_trigger_counter == 0 -> now causes immediate GC; which is OK */
47964
47965         /* Prevent mark-and-sweep and finalizer execution until heap is completely
47966          * initialized.
47967          */
47968         DUK_ASSERT(res->ms_prevent_count == 0);
47969         DUK_ASSERT(res->pf_prevent_count == 0);
47970         res->ms_prevent_count = 1;
47971         res->pf_prevent_count = 1;
47972         DUK_ASSERT(res->ms_running == 0);
47973
47974         res->call_recursion_depth = 0;
47975         res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT;
47976
47977         /* XXX: use the pointer as a seed for now: mix in time at least */
47978
47979         /* The casts through duk_uintptr_t is to avoid the following GCC warning:
47980          *
47981          *   warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
47982          *
47983          * This still generates a /Wp64 warning on VS2010 when compiling for x86.
47984          */
47985 #if defined(DUK_USE_ROM_STRINGS)
47986         /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */
47987         DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED));
47988         res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
47989 #else  /* DUK_USE_ROM_STRINGS */
47990         res->hash_seed = (duk_uint32_t) (duk_uintptr_t) res;
47991 #if !defined(DUK_USE_STRHASH_DENSE)
47992         res->hash_seed ^= 5381;  /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
47993 #endif
47994 #endif  /* DUK_USE_ROM_STRINGS */
47995
47996 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
47997         res->lj.jmpbuf_ptr = NULL;
47998 #endif
47999         DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN);  /* zero */
48000         DUK_ASSERT(res->lj.iserror == 0);
48001         DUK_TVAL_SET_UNDEFINED(&res->lj.value1);
48002         DUK_TVAL_SET_UNDEFINED(&res->lj.value2);
48003
48004         DUK_ASSERT_LJSTATE_UNSET(res);
48005
48006         /*
48007          *  Init stringtable: fixed variant
48008          */
48009
48010         st_initsize = DUK_USE_STRTAB_MINSIZE;
48011 #if defined(DUK_USE_STRTAB_PTRCOMP)
48012         res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * st_initsize);
48013         if (res->strtable16 == NULL) {
48014                 goto failed;
48015         }
48016 #else
48017         res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * st_initsize);
48018         if (res->strtable == NULL) {
48019                 goto failed;
48020         }
48021 #endif
48022         res->st_size = st_initsize;
48023         res->st_mask = st_initsize - 1;
48024 #if (DUK_USE_STRTAB_MINSIZE != DUK_USE_STRTAB_MAXSIZE)
48025         DUK_ASSERT(res->st_count == 0);
48026 #endif
48027
48028 #if defined(DUK_USE_STRTAB_PTRCOMP)
48029         /* zero assumption */
48030         duk_memzero(res->strtable16, sizeof(duk_uint16_t) * st_initsize);
48031 #else
48032 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
48033         {
48034                 duk_uint32_t i;
48035                 for (i = 0; i < st_initsize; i++) {
48036                         res->strtable[i] = NULL;
48037                 }
48038         }
48039 #else
48040         duk_memzero(res->strtable, sizeof(duk_hstring *) * st_initsize);
48041 #endif  /* DUK_USE_EXPLICIT_NULL_INIT */
48042 #endif  /* DUK_USE_STRTAB_PTRCOMP */
48043
48044         /*
48045          *  Init stringcache
48046          */
48047
48048 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
48049         {
48050                 duk_uint_t i;
48051                 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
48052                         res->strcache[i].h = NULL;
48053                 }
48054         }
48055 #endif
48056
48057         /*
48058          *  Init litcache
48059          */
48060 #if defined(DUK_USE_LITCACHE_SIZE)
48061         DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0);
48062         DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE));
48063 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
48064         {
48065                 duk_uint_t i;
48066                 for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
48067                         res->litcache[i].addr = NULL;
48068                         res->litcache[i].h = NULL;
48069                 }
48070         }
48071 #endif
48072 #endif  /* DUK_USE_LITCACHE_SIZE */
48073
48074         /* XXX: error handling is incomplete.  It would be cleanest if
48075          * there was a setjmp catchpoint, so that all init code could
48076          * freely throw errors.  If that were the case, the return code
48077          * passing here could be removed.
48078          */
48079
48080         /*
48081          *  Init built-in strings
48082          */
48083
48084 #if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 2)
48085         goto failed;
48086 #endif
48087         DUK_D(DUK_DPRINT("heap init: initialize heap strings"));
48088         if (!duk__init_heap_strings(res)) {
48089                 goto failed;
48090         }
48091
48092         /*
48093          *  Init the heap thread
48094          */
48095
48096 #if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 3)
48097         goto failed;
48098 #endif
48099         DUK_D(DUK_DPRINT("heap init: initialize heap thread"));
48100         if (!duk__init_heap_thread(res)) {
48101                 goto failed;
48102         }
48103
48104         /*
48105          *  Init the heap object
48106          */
48107
48108 #if defined(DUK_USE_INJECT_HEAP_ALLOC_ERROR) && (DUK_USE_INJECT_HEAP_ALLOC_ERROR == 4)
48109         goto failed;
48110 #endif
48111         DUK_D(DUK_DPRINT("heap init: initialize heap object"));
48112         DUK_ASSERT(res->heap_thread != NULL);
48113         res->heap_object = duk_hobject_alloc_unchecked(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
48114                                                             DUK_HOBJECT_FLAG_FASTREFS |
48115                                                             DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
48116         if (res->heap_object == NULL) {
48117                 goto failed;
48118         }
48119         DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
48120
48121         /*
48122          *  Odds and ends depending on the heap thread
48123          */
48124
48125 #if !defined(DUK_USE_GET_RANDOM_DOUBLE)
48126 #if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
48127         res->rnd_state = (duk_uint32_t) duk_time_get_ecmascript_time(res->heap_thread);
48128         duk_util_tinyrandom_prepare_seed(res->heap_thread);
48129 #else
48130         res->rnd_state[0] = (duk_uint64_t) duk_time_get_ecmascript_time(res->heap_thread);
48131         DUK_ASSERT(res->rnd_state[1] == 0);  /* Not filled here, filled in by seed preparation. */
48132 #if 0  /* Manual test values matching misc/xoroshiro128plus_test.c. */
48133         res->rnd_state[0] = DUK_U64_CONSTANT(0xdeadbeef12345678);
48134         res->rnd_state[1] = DUK_U64_CONSTANT(0xcafed00d12345678);
48135 #endif
48136         duk_util_tinyrandom_prepare_seed(res->heap_thread);
48137         /* Mix in heap pointer: this ensures that if two Duktape heaps are
48138          * created on the same millisecond, they get a different PRNG
48139          * sequence (unless e.g. virtual memory addresses cause also the
48140          * heap object pointer to be the same).
48141          */
48142         {
48143                 duk_uint64_t tmp_u64;
48144                 tmp_u64 = 0;
48145                 duk_memcpy((void *) &tmp_u64,
48146                            (const void *) &res,
48147                            (size_t) (sizeof(void *) >= sizeof(duk_uint64_t) ? sizeof(duk_uint64_t) : sizeof(void *)));
48148                 res->rnd_state[1] ^= tmp_u64;
48149         }
48150         do {
48151                 duk_small_uint_t i;
48152                 for (i = 0; i < 10; i++) {
48153                         /* Throw away a few initial random numbers just in
48154                          * case.  Probably unnecessary due to SplitMix64
48155                          * preparation.
48156                          */
48157                         (void) duk_util_tinyrandom_get_double(res->heap_thread);
48158                 }
48159         } while (0);
48160 #endif
48161 #endif
48162
48163         /*
48164          *  Allow finalizer and mark-and-sweep processing.
48165          */
48166
48167         DUK_D(DUK_DPRINT("heap init: allow finalizer/mark-and-sweep processing"));
48168         DUK_ASSERT(res->ms_prevent_count == 1);
48169         DUK_ASSERT(res->pf_prevent_count == 1);
48170         res->ms_prevent_count = 0;
48171         res->pf_prevent_count = 0;
48172         DUK_ASSERT(res->ms_running == 0);
48173 #if defined(DUK_USE_ASSERTIONS)
48174         res->heap_initializing = 0;
48175 #endif
48176
48177         /*
48178          *  All done.
48179          */
48180
48181         DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
48182         return res;
48183
48184  failed:
48185         DUK_D(DUK_DPRINT("heap allocation failed"));
48186
48187         if (res != NULL) {
48188                 /* Assumes that allocated pointers and alloc funcs are valid
48189                  * if res exists.
48190                  */
48191                 DUK_ASSERT(res->ms_prevent_count == 1);
48192                 DUK_ASSERT(res->pf_prevent_count == 1);
48193                 DUK_ASSERT(res->ms_running == 0);
48194                 if (res->heap_thread != NULL) {
48195                         res->ms_prevent_count = 0;
48196                         res->pf_prevent_count = 0;
48197                 }
48198 #if defined(DUK_USE_ASSERTIONS)
48199                 res->heap_initializing = 0;
48200 #endif
48201
48202                 DUK_ASSERT(res->alloc_func != NULL);
48203                 DUK_ASSERT(res->realloc_func != NULL);
48204                 DUK_ASSERT(res->free_func != NULL);
48205                 duk_heap_free(res);
48206         }
48207
48208         return NULL;
48209 }
48210
48211 /* automatic undefs */
48212 #undef DUK__DUMPLM_SIGNED
48213 #undef DUK__DUMPLM_SIGNED_RAW
48214 #undef DUK__DUMPLM_UNSIGNED
48215 #undef DUK__DUMPLM_UNSIGNED_RAW
48216 #undef DUK__DUMPSZ
48217 #undef DUK__FIXED_HASH_SEED
48218 #line 1 "duk_heap_finalize.c"
48219 /*
48220  *  Finalizer handling.
48221  */
48222
48223 /* #include duk_internal.h -> already included */
48224
48225 #if defined(DUK_USE_FINALIZER_SUPPORT)
48226
48227 /*
48228  *  Fake torture finalizer.
48229  */
48230
48231 #if defined(DUK_USE_FINALIZER_TORTURE)
48232 DUK_LOCAL duk_ret_t duk__fake_global_finalizer(duk_hthread *thr) {
48233         DUK_DD(DUK_DDPRINT("fake global torture finalizer executed"));
48234
48235         /* Require a lot of stack to force a value stack grow/shrink. */
48236         duk_require_stack(thr, 100000);
48237
48238         /* Force a reallocation with pointer change for value stack
48239          * to maximize side effects.
48240          */
48241         duk_hthread_valstack_torture_realloc(thr);
48242
48243         /* Inner function call, error throw. */
48244         duk_eval_string_noresult(thr,
48245                 "(function dummy() {\n"
48246                 "    dummy.prototype = null;  /* break reference loop */\n"
48247                 "    try {\n"
48248                 "        throw 'fake-finalizer-dummy-error';\n"
48249                 "    } catch (e) {\n"
48250                 "        void e;\n"
48251                 "    }\n"
48252                 "})()");
48253
48254         /* The above creates garbage (e.g. a function instance).  Because
48255          * the function/prototype reference loop is broken, it gets collected
48256          * immediately by DECREF.  If Function.prototype has a _Finalizer
48257          * property (happens in some test cases), the garbage gets queued to
48258          * finalize_list.  This still won't cause an infinite loop because
48259          * the torture finalizer is called once per finalize_list run and
48260          * the garbage gets handled in the same run.  (If the garbage needs
48261          * mark-and-sweep collection, an infinite loop might ensue.)
48262          */
48263         return 0;
48264 }
48265
48266 DUK_LOCAL void duk__run_global_torture_finalizer(duk_hthread *thr) {
48267         DUK_ASSERT(thr != NULL);
48268
48269         /* Avoid fake finalization when callstack limit is near.  Otherwise
48270          * a callstack limit error will be created, then refzero'ed.  The
48271          * +5 headroom is conservative.
48272          */
48273         if (thr->heap->call_recursion_depth + 5 >= thr->heap->call_recursion_limit ||
48274             thr->callstack_top + 5 >= DUK_USE_CALLSTACK_LIMIT) {
48275                 DUK_D(DUK_DPRINT("skip global torture finalizer, too little headroom for call recursion or call stack size"));
48276                 return;
48277         }
48278
48279         /* Run fake finalizer.  Avoid creating unnecessary garbage. */
48280         duk_push_c_function(thr, duk__fake_global_finalizer, 0 /*nargs*/);
48281         (void) duk_pcall(thr, 0 /*nargs*/);
48282         duk_pop(thr);
48283 }
48284 #endif  /* DUK_USE_FINALIZER_TORTURE */
48285
48286 /*
48287  *  Process the finalize_list to completion.
48288  *
48289  *  An object may be placed on finalize_list by either refcounting or
48290  *  mark-and-sweep.  The refcount of objects placed by refcounting will be
48291  *  zero; the refcount of objects placed by mark-and-sweep is > 0.  In both
48292  *  cases the refcount is bumped by 1 artificially so that a REFZERO event
48293  *  can never happen while an object is waiting for finalization.  Without
48294  *  this bump a REFZERO could now happen because user code may call
48295  *  duk_push_heapptr() and then pop a value even when it's on finalize_list.
48296  *
48297  *  List processing assumes refcounts are kept up-to-date at all times, so
48298  *  that once the finalizer returns, a zero refcount is a reliable reason to
48299  *  free the object immediately rather than place it back to the heap.  This
48300  *  is the case because we run outside of refzero_list processing so that
48301  *  DECREF cascades are handled fully inline.
48302  *
48303  *  For mark-and-sweep queued objects (had_zero_refcount false) the object
48304  *  may be freed immediately if its refcount is zero after the finalizer call
48305  *  (i.e. finalizer removed the reference loop for the object).  If not, the
48306  *  next mark-and-sweep will collect the object unless it has become reachable
48307  *  (i.e. rescued) by that time and its refcount hasn't fallen to zero before
48308  *  that.  Mark-and-sweep detects these objects because their FINALIZED flag
48309  *  is set.
48310  *
48311  *  There's an inherent limitation for mark-and-sweep finalizer rescuing: an
48312  *  object won't get refinalized if (1) it's rescued, but (2) becomes
48313  *  unreachable before mark-and-sweep has had time to notice it.  The next
48314  *  mark-and-sweep round simply doesn't have any information of whether the
48315  *  object has been unreachable the whole time or not (the only way to get
48316  *  that information would be a mark-and-sweep pass for *every finalized
48317  *  object*).  This is awkward for the application because the mark-and-sweep
48318  *  round is not generally visible or under full application control.
48319  *
48320  *  For refcount queued objects (had_zero_refcount true) the object is either
48321  *  immediately freed or rescued, and waiting for a mark-and-sweep round is not
48322  *  necessary (or desirable); FINALIZED is cleared when a rescued object is
48323  *  queued back to heap_allocated.  The object is eligible for finalization
48324  *  again (either via refcounting or mark-and-sweep) immediately after being
48325  *  rescued.  If a refcount finalized object is placed into an unreachable
48326  *  reference loop by its finalizer, it will get collected by mark-and-sweep
48327  *  and currently the finalizer will execute again.
48328  *
48329  *  There's a special case where:
48330  *
48331  *    - Mark-and-sweep queues an object to finalize_list for finalization.
48332  *    - The finalizer is executed, FINALIZED is set, and object is queued
48333  *      back to heap_allocated, waiting for a new mark-and-sweep round.
48334  *    - The object's refcount drops to zero before mark-and-sweep has a
48335  *      chance to run another round and make a rescue/free decision.
48336  *
48337  *  This is now handled by refzero code: if an object has a finalizer but
48338  *  FINALIZED is already set, the object is freed without finalizer processing.
48339  *  The outcome is the same as if mark-and-sweep was executed at that point;
48340  *  mark-and-sweep would also free the object without another finalizer run.
48341  *  This could also be changed so that the refzero-triggered finalizer *IS*
48342  *  executed: being refzero collected implies someone has operated on the
48343  *  object so it hasn't been totally unreachable the whole time.  This would
48344  *  risk a finalizer loop however.
48345  */
48346
48347 DUK_INTERNAL void duk_heap_process_finalize_list(duk_heap *heap) {
48348         duk_heaphdr *curr;
48349 #if defined(DUK_USE_DEBUG)
48350         duk_size_t count = 0;
48351 #endif
48352
48353         DUK_DDD(DUK_DDDPRINT("duk_heap_process_finalize_list: %p", (void *) heap));
48354
48355         if (heap->pf_prevent_count != 0) {
48356                 DUK_DDD(DUK_DDDPRINT("skip finalize_list processing: pf_prevent_count != 0"));
48357                 return;
48358         }
48359
48360         /* Heap alloc prevents mark-and-sweep before heap_thread is ready. */
48361         DUK_ASSERT(heap != NULL);
48362         DUK_ASSERT(heap->heap_thread != NULL);
48363         DUK_ASSERT(heap->heap_thread->valstack != NULL);
48364 #if defined(DUK_USE_REFERENCE_COUNTING)
48365         DUK_ASSERT(heap->refzero_list == NULL);
48366 #endif
48367
48368         DUK_ASSERT(heap->pf_prevent_count == 0);
48369         heap->pf_prevent_count = 1;
48370
48371         /* Mark-and-sweep no longer needs to be prevented when running
48372          * finalizers: mark-and-sweep skips any rescue decisions if there
48373          * are any objects in finalize_list when mark-and-sweep is entered.
48374          * This protects finalized objects from incorrect rescue decisions
48375          * caused by finalize_list being a reachability root and only
48376          * partially processed.  Freeing decisions are not postponed.
48377          */
48378
48379         /* When finalizer torture is enabled, make a fake finalizer call with
48380          * maximum side effects regardless of whether finalize_list is empty.
48381          */
48382 #if defined(DUK_USE_FINALIZER_TORTURE)
48383         duk__run_global_torture_finalizer(heap->heap_thread);
48384 #endif
48385
48386         /* Process finalize_list until it becomes empty.  There's currently no
48387          * protection against a finalizer always creating more garbage.
48388          */
48389         while ((curr = heap->finalize_list) != NULL) {
48390 #if defined(DUK_USE_REFERENCE_COUNTING)
48391                 duk_bool_t queue_back;
48392 #endif
48393
48394                 DUK_DD(DUK_DDPRINT("processing finalize_list entry: %p -> %!iO", (void *) curr, curr));
48395
48396                 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);  /* Only objects have finalizers. */
48397                 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
48398                 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
48399                 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(curr));  /* All objects on finalize_list will have this flag (except object being finalized right now). */
48400                 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));   /* Queueing code ensures. */
48401                 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr));  /* ROM objects never get freed (or finalized). */
48402
48403 #if defined(DUK_USE_ASSERTIONS)
48404                 DUK_ASSERT(heap->currently_finalizing == NULL);
48405                 heap->currently_finalizing = curr;
48406 #endif
48407
48408                 /* Clear FINALIZABLE for object being finalized, so that
48409                  * duk_push_heapptr() can properly ignore the object.
48410                  */
48411                 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
48412
48413                 if (DUK_LIKELY(!heap->pf_skip_finalizers)) {
48414                         /* Run the finalizer, duk_heap_run_finalizer() sets
48415                          * and checks for FINALIZED to prevent the finalizer
48416                          * from executing multiple times per finalization cycle.
48417                          * (This safeguard shouldn't be actually needed anymore).
48418                          */
48419
48420 #if defined(DUK_USE_REFERENCE_COUNTING)
48421                         duk_bool_t had_zero_refcount;
48422 #endif
48423
48424                         /* The object's refcount is >0 throughout so it won't be
48425                          * refzero processed prematurely.
48426                          */
48427 #if defined(DUK_USE_REFERENCE_COUNTING)
48428                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);
48429                         had_zero_refcount = (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1);  /* Preincremented on finalize_list insert. */
48430 #endif
48431
48432                         DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
48433                         duk_heap_run_finalizer(heap, (duk_hobject *) curr);  /* must never longjmp */
48434                         DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
48435                         /* XXX: assert that object is still in finalize_list
48436                          * when duk_push_heapptr() allows automatic rescue.
48437                          */
48438
48439 #if defined(DUK_USE_REFERENCE_COUNTING)
48440                         DUK_DD(DUK_DDPRINT("refcount after finalizer (includes bump): %ld", (long) DUK_HEAPHDR_GET_REFCOUNT(curr)));
48441                         if (DUK_HEAPHDR_GET_REFCOUNT(curr) == 1) {  /* Only artificial bump in refcount? */
48442 #if defined(DUK_USE_DEBUG)
48443                                 if (had_zero_refcount) {
48444                                         DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (refcount queued)"));
48445                                 } else {
48446                                         DUK_DD(DUK_DDPRINT("finalized object's refcount is zero -> free immediately (mark-and-sweep queued)"));
48447                                 }
48448 #endif
48449                                 queue_back = 0;
48450                         } else
48451 #endif
48452                         {
48453 #if defined(DUK_USE_REFERENCE_COUNTING)
48454                                 queue_back = 1;
48455                                 if (had_zero_refcount) {
48456                                         /* When finalization is triggered
48457                                          * by refzero and we queue the object
48458                                          * back, clear FINALIZED right away
48459                                          * so that the object can be refinalized
48460                                          * immediately if necessary.
48461                                          */
48462                                         DUK_HEAPHDR_CLEAR_FINALIZED(curr);
48463                                 }
48464 #endif
48465                         }
48466                 } else {
48467                         /* Used during heap destruction: don't actually run finalizers
48468                          * because we're heading into forced finalization.  Instead,
48469                          * queue finalizable objects back to the heap_allocated list.
48470                          */
48471                         DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
48472                         DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
48473 #if defined(DUK_USE_REFERENCE_COUNTING)
48474                         queue_back = 1;
48475 #endif
48476                 }
48477
48478                 /* Dequeue object from finalize_list.  Note that 'curr' may no
48479                  * longer be finalize_list head because new objects may have
48480                  * been queued to the list.  As a result we can't optimize for
48481                  * the single-linked heap case and must scan the list for
48482                  * removal, typically the scan is very short however.
48483                  */
48484                 DUK_HEAP_REMOVE_FROM_FINALIZE_LIST(heap, curr);
48485
48486                 /* Queue back to heap_allocated or free immediately. */
48487 #if defined(DUK_USE_REFERENCE_COUNTING)
48488                 if (queue_back) {
48489                         /* FINALIZED is only cleared if object originally
48490                          * queued for finalization by refcounting.  For
48491                          * mark-and-sweep FINALIZED is left set, so that
48492                          * next mark-and-sweep round can make a rescue/free
48493                          * decision.
48494                          */
48495                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) >= 1);
48496                         DUK_HEAPHDR_PREDEC_REFCOUNT(curr);  /* Remove artificial refcount bump. */
48497                         DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
48498                         DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
48499                 } else {
48500                         /* No need to remove the refcount bump here. */
48501                         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);  /* currently, always the case */
48502                         DUK_DD(DUK_DDPRINT("refcount finalize after finalizer call: %!O", curr));
48503                         duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr);
48504                         duk_free_hobject(heap, (duk_hobject *) curr);
48505                         DUK_DD(DUK_DDPRINT("freed hobject after finalization: %p", (void *) curr));
48506                 }
48507 #else  /* DUK_USE_REFERENCE_COUNTING */
48508                 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
48509                 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
48510 #endif  /* DUK_USE_REFERENCE_COUNTING */
48511
48512 #if defined(DUK_USE_DEBUG)
48513                 count++;
48514 #endif
48515
48516 #if defined(DUK_USE_ASSERTIONS)
48517                 DUK_ASSERT(heap->currently_finalizing != NULL);
48518                 heap->currently_finalizing = NULL;
48519 #endif
48520         }
48521
48522         /* finalize_list will always be processed completely. */
48523         DUK_ASSERT(heap->finalize_list == NULL);
48524
48525 #if 0
48526         /* While NORZ macros are used above, this is unnecessary because the
48527          * only pending side effects are now finalizers, and finalize_list is
48528          * empty.
48529          */
48530         DUK_REFZERO_CHECK_SLOW(heap->heap_thread);
48531 #endif
48532
48533         /* Prevent count may be bumped while finalizers run, but should always
48534          * be reliably unbumped by the time we get here.
48535          */
48536         DUK_ASSERT(heap->pf_prevent_count == 1);
48537         heap->pf_prevent_count = 0;
48538
48539 #if defined(DUK_USE_DEBUG)
48540         DUK_DD(DUK_DDPRINT("duk_heap_process_finalize_list: %ld finalizers called", (long) count));
48541 #endif
48542 }
48543
48544 /*
48545  *  Run an duk_hobject finalizer.  Must never throw an uncaught error
48546  *  (but may throw caught errors).
48547  *
48548  *  There is no return value.  Any return value or error thrown by
48549  *  the finalizer is ignored (although errors are debug logged).
48550  *
48551  *  Notes:
48552  *
48553  *    - The finalizer thread 'top' assertions are there because it is
48554  *      critical that strict stack policy is observed (i.e. no cruft
48555  *      left on the finalizer stack).
48556  */
48557
48558 DUK_LOCAL duk_ret_t duk__finalize_helper(duk_hthread *thr, void *udata) {
48559         DUK_ASSERT(thr != NULL);
48560         DUK_UNREF(udata);
48561
48562         DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
48563
48564         /* [... obj] */
48565
48566         /* _Finalizer property is read without checking if the value is
48567          * callable or even exists.  This is intentional, and handled
48568          * by throwing an error which is caught by the safe call wrapper.
48569          *
48570          * XXX: Finalizer lookup should traverse the prototype chain (to allow
48571          * inherited finalizers) but should not invoke accessors or proxy object
48572          * behavior.  At the moment this lookup will invoke proxy behavior, so
48573          * caller must ensure that this function is not called if the target is
48574          * a Proxy.
48575          */
48576         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FINALIZER);  /* -> [... obj finalizer] */
48577         duk_dup_m2(thr);
48578         duk_push_boolean(thr, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
48579         DUK_DDD(DUK_DDDPRINT("calling finalizer"));
48580         duk_call(thr, 2);  /* [ ... obj finalizer obj heapDestruct ]  -> [ ... obj retval ] */
48581         DUK_DDD(DUK_DDDPRINT("finalizer returned successfully"));
48582         return 0;
48583
48584         /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
48585          * so we don't need to pop stuff here.  There is no return value;
48586          * caller determines rescued status based on object refcount.
48587          */
48588 }
48589
48590 DUK_INTERNAL void duk_heap_run_finalizer(duk_heap *heap, duk_hobject *obj) {
48591         duk_hthread *thr;
48592         duk_ret_t rc;
48593 #if defined(DUK_USE_ASSERTIONS)
48594         duk_idx_t entry_top;
48595 #endif
48596
48597         DUK_DD(DUK_DDPRINT("running duk_hobject finalizer for object: %p", (void *) obj));
48598
48599         DUK_ASSERT(heap != NULL);
48600         DUK_ASSERT(heap->heap_thread != NULL);
48601         thr = heap->heap_thread;
48602         DUK_ASSERT(obj != NULL);
48603         DUK_ASSERT_VALSTACK_SPACE(heap->heap_thread, 1);
48604
48605 #if defined(DUK_USE_ASSERTIONS)
48606         entry_top = duk_get_top(thr);
48607 #endif
48608         /*
48609          *  Get and call the finalizer.  All of this must be wrapped
48610          *  in a protected call, because even getting the finalizer
48611          *  may trigger an error (getter may throw one, for instance).
48612          */
48613
48614         /* ROM objects could inherit a finalizer, but they are never deemed
48615          * unreachable by mark-and-sweep, and their refcount never falls to 0.
48616          */
48617         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
48618
48619         /* Duktape 2.1: finalize_list never contains objects with FINALIZED
48620          * set, so no need to check here.
48621          */
48622         DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj));
48623 #if 0
48624         if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
48625                 DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
48626                 return;
48627         }
48628 #endif
48629         DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj);  /* ensure never re-entered until rescue cycle complete */
48630
48631 #if defined(DUK_USE_ES6_PROXY)
48632         if (DUK_HOBJECT_IS_PROXY(obj)) {
48633                 /* This may happen if duk_set_finalizer() or Duktape.fin() is
48634                  * called for a Proxy object.  In such cases the fast finalizer
48635                  * flag will be set on the Proxy, not the target, and neither
48636                  * will be finalized.
48637                  */
48638                 DUK_D(DUK_DPRINT("object is a Proxy, skip finalizer call"));
48639                 return;
48640         }
48641 #endif  /* DUK_USE_ES6_PROXY */
48642
48643         duk_push_hobject(thr, obj);  /* this also increases refcount by one */
48644         rc = duk_safe_call(thr, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/);  /* -> [... obj retval/error] */
48645         DUK_ASSERT_TOP(thr, entry_top + 2);  /* duk_safe_call discipline */
48646
48647         if (rc != DUK_EXEC_SUCCESS) {
48648                 /* Note: we ask for one return value from duk_safe_call to get this
48649                  * error debugging here.
48650                  */
48651                 DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
48652                                  (void *) obj, (duk_tval *) duk_get_tval(thr, -1)));
48653         }
48654         duk_pop_2(thr);  /* -> [...] */
48655
48656         DUK_ASSERT_TOP(thr, entry_top);
48657 }
48658
48659 #else  /* DUK_USE_FINALIZER_SUPPORT */
48660
48661 /* nothing */
48662
48663 #endif  /* DUK_USE_FINALIZER_SUPPORT */
48664 #line 1 "duk_heap_hashstring.c"
48665 /*
48666  *  String hash computation (interning).
48667  *
48668  *  String hashing is performance critical because a string hash is computed
48669  *  for all new strings which are candidates to be added to the string table.
48670  *  However, strings actually added to the string table go through a codepoint
48671  *  length calculation which dominates performance because it goes through
48672  *  every byte of the input string (but only for strings added).
48673  *
48674  *  The string hash algorithm should be fast, but on the other hand provide
48675  *  good enough hashes to ensure both string table and object property table
48676  *  hash tables work reasonably well (i.e., there aren't too many collisions
48677  *  with real world inputs).  Unless the hash is cryptographic, it's always
48678  *  possible to craft inputs with maximal hash collisions.
48679  *
48680  *  NOTE: The hash algorithms must match tools/dukutil.py:duk_heap_hashstring()
48681  *  for ROM string support!
48682  */
48683
48684 /* #include duk_internal.h -> already included */
48685
48686 #if defined(DUK_USE_STRHASH_DENSE)
48687 /* Constants for duk_hashstring(). */
48688 #define DUK__STRHASH_SHORTSTRING   4096L
48689 #define DUK__STRHASH_MEDIUMSTRING  (256L * 1024L)
48690 #define DUK__STRHASH_BLOCKSIZE     256L
48691
48692 DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
48693         duk_uint32_t hash;
48694
48695         /* Use Murmurhash2 directly for short strings, and use "block skipping"
48696          * for long strings: hash an initial part and then sample the rest of
48697          * the string with reasonably sized chunks.  An initial offset for the
48698          * sampling is computed based on a hash of the initial part of the string;
48699          * this is done to (usually) avoid the case where all long strings have
48700          * certain offset ranges which are never sampled.
48701          *
48702          * Skip should depend on length and bound the total time to roughly
48703          * logarithmic.  With current values:
48704          *
48705          *   1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
48706          *   1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
48707          *
48708          * XXX: It would be better to compute the skip offset more "smoothly"
48709          * instead of having a few boundary values.
48710          */
48711
48712         /* note: mixing len into seed improves hashing when skipping */
48713         duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len);
48714
48715         if (len <= DUK__STRHASH_SHORTSTRING) {
48716                 hash = duk_util_hashbytes(str, len, str_seed);
48717         } else {
48718                 duk_size_t off;
48719                 duk_size_t skip;
48720
48721                 if (len <= DUK__STRHASH_MEDIUMSTRING) {
48722                         skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
48723                 } else {
48724                         skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
48725                 }
48726
48727                 hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed);
48728                 off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256;
48729
48730                 /* XXX: inefficient loop */
48731                 while (off < len) {
48732                         duk_size_t left = len - off;
48733                         duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left);
48734                         hash ^= duk_util_hashbytes(str + off, now, str_seed);
48735                         off += skip;
48736                 }
48737         }
48738
48739 #if defined(DUK_USE_STRHASH16)
48740         /* Truncate to 16 bits here, so that a computed hash can be compared
48741          * against a hash stored in a 16-bit field.
48742          */
48743         hash &= 0x0000ffffUL;
48744 #endif
48745         return hash;
48746 }
48747 #else  /* DUK_USE_STRHASH_DENSE */
48748 DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
48749         duk_uint32_t hash;
48750         duk_size_t step;
48751         duk_size_t off;
48752
48753         /* Slightly modified "Bernstein hash" from:
48754          *
48755          *     http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
48756          *
48757          * Modifications: string skipping and reverse direction similar to
48758          * Lua 5.1.5, and different hash initializer.
48759          *
48760          * The reverse direction ensures last byte it always included in the
48761          * hash which is a good default as changing parts of the string are
48762          * more often in the suffix than in the prefix.
48763          */
48764
48765         hash = heap->hash_seed ^ ((duk_uint32_t) len);  /* Bernstein hash init value is normally 5381 */
48766         step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1;
48767         for (off = len; off >= step; off -= step) {
48768                 DUK_ASSERT(off >= 1);  /* off >= step, and step >= 1 */
48769                 hash = (hash * 33) + str[off - 1];
48770         }
48771
48772 #if defined(DUK_USE_STRHASH16)
48773         /* Truncate to 16 bits here, so that a computed hash can be compared
48774          * against a hash stored in a 16-bit field.
48775          */
48776         hash &= 0x0000ffffUL;
48777 #endif
48778         return hash;
48779 }
48780 #endif  /* DUK_USE_STRHASH_DENSE */
48781
48782 /* automatic undefs */
48783 #undef DUK__STRHASH_BLOCKSIZE
48784 #undef DUK__STRHASH_MEDIUMSTRING
48785 #undef DUK__STRHASH_SHORTSTRING
48786 #line 1 "duk_heap_markandsweep.c"
48787 /*
48788  *  Mark-and-sweep garbage collection.
48789  */
48790
48791 /* #include duk_internal.h -> already included */
48792
48793 DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
48794 DUK_LOCAL_DECL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h);
48795 DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv);
48796 DUK_LOCAL_DECL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count);
48797
48798 /*
48799  *  Marking functions for heap types: mark children recursively.
48800  */
48801
48802 DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) {
48803         DUK_UNREF(heap);
48804         DUK_UNREF(h);
48805
48806         DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h));
48807         DUK_ASSERT(h);
48808
48809         /* nothing to process */
48810 }
48811
48812 DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
48813         duk_uint_fast32_t i;
48814
48815         DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));
48816
48817         DUK_ASSERT(h);
48818
48819         /* XXX: use advancing pointers instead of index macros -> faster and smaller? */
48820
48821         for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
48822                 duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
48823                 if (key == NULL) {
48824                         continue;
48825                 }
48826                 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) key);
48827                 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
48828                         duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
48829                         duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
48830                 } else {
48831                         duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
48832                 }
48833         }
48834
48835         for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
48836                 duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
48837         }
48838
48839         /* Hash part is a 'weak reference' and does not contribute. */
48840
48841         duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
48842
48843         /* Fast path for objects which don't have a subclass struct, or have a
48844          * subclass struct but nothing that needs marking in the subclass struct.
48845          */
48846         if (DUK_HOBJECT_HAS_FASTREFS(h)) {
48847                 DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h));
48848                 return;
48849         }
48850         DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h));
48851
48852         /* XXX: reorg, more common first */
48853         if (DUK_HOBJECT_IS_COMPFUNC(h)) {
48854                 duk_hcompfunc *f = (duk_hcompfunc *) h;
48855                 duk_tval *tv, *tv_end;
48856                 duk_hobject **fn, **fn_end;
48857
48858                 DUK_ASSERT_HCOMPFUNC_VALID(f);
48859
48860                 /* 'data' is reachable through every compiled function which
48861                  * contains a reference.
48862                  */
48863
48864                 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_DATA(heap, f));
48865                 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f));
48866                 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f));
48867
48868                 if (DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL) {
48869                         tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
48870                         tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
48871                         while (tv < tv_end) {
48872                                 duk__mark_tval(heap, tv);
48873                                 tv++;
48874                         }
48875
48876                         fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
48877                         fn_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
48878                         while (fn < fn_end) {
48879                                 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) *fn);
48880                                 fn++;
48881                         }
48882                 } else {
48883                         /* May happen in some out-of-memory corner cases. */
48884                         DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking"));
48885                 }
48886         } else if (DUK_HOBJECT_IS_DECENV(h)) {
48887                 duk_hdecenv *e = (duk_hdecenv *) h;
48888                 DUK_ASSERT_HDECENV_VALID(e);
48889                 duk__mark_heaphdr(heap, (duk_heaphdr *) e->thread);
48890                 duk__mark_heaphdr(heap, (duk_heaphdr *) e->varmap);
48891         } else if (DUK_HOBJECT_IS_OBJENV(h)) {
48892                 duk_hobjenv *e = (duk_hobjenv *) h;
48893                 DUK_ASSERT_HOBJENV_VALID(e);
48894                 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) e->target);
48895 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
48896         } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
48897                 duk_hbufobj *b = (duk_hbufobj *) h;
48898                 DUK_ASSERT_HBUFOBJ_VALID(b);
48899                 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
48900                 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop);
48901 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
48902         } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
48903                 duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
48904                 DUK_ASSERT_HBOUNDFUNC_VALID(f);
48905                 duk__mark_tval(heap, &f->target);
48906                 duk__mark_tval(heap, &f->this_binding);
48907                 duk__mark_tvals(heap, f->args, f->nargs);
48908 #if defined(DUK_USE_ES6_PROXY)
48909         } else if (DUK_HOBJECT_IS_PROXY(h)) {
48910                 duk_hproxy *p = (duk_hproxy *) h;
48911                 DUK_ASSERT_HPROXY_VALID(p);
48912                 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->target);
48913                 duk__mark_heaphdr_nonnull(heap, (duk_heaphdr *) p->handler);
48914 #endif  /* DUK_USE_ES6_PROXY */
48915         } else if (DUK_HOBJECT_IS_THREAD(h)) {
48916                 duk_hthread *t = (duk_hthread *) h;
48917                 duk_activation *act;
48918                 duk_tval *tv;
48919
48920                 DUK_ASSERT_HTHREAD_VALID(t);
48921
48922                 tv = t->valstack;
48923                 while (tv < t->valstack_top) {
48924                         duk__mark_tval(heap, tv);
48925                         tv++;
48926                 }
48927
48928                 for (act = t->callstack_curr; act != NULL; act = act->parent) {
48929                         duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
48930                         duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
48931                         duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
48932 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
48933                         duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
48934 #endif
48935 #if 0  /* nothing now */
48936                         for (cat = act->cat; cat != NULL; cat = cat->parent) {
48937                         }
48938 #endif
48939                 }
48940
48941                 duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
48942
48943                 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
48944                         duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
48945                 }
48946         } else {
48947                 /* We may come here if the object should have a FASTREFS flag
48948                  * but it's missing for some reason.  Assert for never getting
48949                  * here; however, other than performance, this is harmless.
48950                  */
48951                 DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h));
48952                 DUK_ASSERT(0);
48953         }
48954 }
48955
48956 /* Mark any duk_heaphdr type.  Recursion tracking happens only here. */
48957 DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
48958         DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
48959                              (void *) h,
48960                              (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
48961
48962         /* XXX: add non-null variant? */
48963         if (h == NULL) {
48964                 return;
48965         }
48966
48967         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h) || DUK_HEAPHDR_HAS_REACHABLE(h));
48968
48969 #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
48970         if (!DUK_HEAPHDR_HAS_READONLY(h)) {
48971                 h->h_assert_refcount++;  /* Comparison refcount: bump even if already reachable. */
48972         }
48973 #endif
48974         if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
48975                 DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
48976                 return;
48977         }
48978 #if defined(DUK_USE_ROM_OBJECTS)
48979         /* READONLY objects always have REACHABLE set, so the check above
48980          * will prevent READONLY objects from being marked here.
48981          */
48982         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(h));
48983 #endif
48984
48985         DUK_HEAPHDR_SET_REACHABLE(h);
48986
48987         if (heap->ms_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
48988                 DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h));
48989                 DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap);
48990                 DUK_HEAPHDR_SET_TEMPROOT(h);
48991                 return;
48992         }
48993
48994         heap->ms_recursion_depth++;
48995         DUK_ASSERT(heap->ms_recursion_depth != 0);  /* Wrap. */
48996
48997         switch (DUK_HEAPHDR_GET_TYPE(h)) {
48998         case DUK_HTYPE_STRING:
48999                 duk__mark_hstring(heap, (duk_hstring *) h);
49000                 break;
49001         case DUK_HTYPE_OBJECT:
49002                 duk__mark_hobject(heap, (duk_hobject *) h);
49003                 break;
49004         case DUK_HTYPE_BUFFER:
49005                 /* nothing to mark */
49006                 break;
49007         default:
49008                 DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h)));
49009                 DUK_UNREACHABLE();
49010         }
49011
49012         DUK_ASSERT(heap->ms_recursion_depth > 0);
49013         heap->ms_recursion_depth--;
49014 }
49015
49016 DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
49017         DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv));
49018         if (tv == NULL) {
49019                 return;
49020         }
49021         if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
49022                 duk_heaphdr *h;
49023                 h = DUK_TVAL_GET_HEAPHDR(tv);
49024                 DUK_ASSERT(h != NULL);
49025                 duk__mark_heaphdr_nonnull(heap, h);
49026         }
49027 }
49028
49029 DUK_LOCAL void duk__mark_tvals(duk_heap *heap, duk_tval *tv, duk_idx_t count) {
49030         DUK_ASSERT(count == 0 || tv != NULL);
49031
49032         while (count-- > 0) {
49033                 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
49034                         duk_heaphdr *h;
49035                         h = DUK_TVAL_GET_HEAPHDR(tv);
49036                         DUK_ASSERT(h != NULL);
49037                         duk__mark_heaphdr_nonnull(heap, h);
49038                 }
49039                 tv++;
49040         }
49041 }
49042
49043 /* Mark any duk_heaphdr type, caller guarantees a non-NULL pointer. */
49044 DUK_LOCAL void duk__mark_heaphdr_nonnull(duk_heap *heap, duk_heaphdr *h) {
49045         /* For now, just call the generic handler.  Change when call sites
49046          * are changed too.
49047          */
49048         duk__mark_heaphdr(heap, h);
49049 }
49050
49051 /*
49052  *  Mark the heap.
49053  */
49054
49055 DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) {
49056         duk_small_uint_t i;
49057
49058         DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap));
49059
49060         duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread);
49061         duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object);
49062
49063         for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
49064                 duk_hstring *h = DUK_HEAP_GET_STRING(heap, i);
49065                 duk__mark_heaphdr(heap, (duk_heaphdr *) h);
49066         }
49067
49068         duk__mark_tval(heap, &heap->lj.value1);
49069         duk__mark_tval(heap, &heap->lj.value2);
49070
49071 #if defined(DUK_USE_DEBUGGER_SUPPORT)
49072         for (i = 0; i < heap->dbg_breakpoint_count; i++) {
49073                 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename);
49074         }
49075 #endif
49076 }
49077
49078 /*
49079  *  Mark unreachable, finalizable objects.
49080  *
49081  *  Such objects will be moved aside and their finalizers run later.  They
49082  *  have to be treated as reachability roots for their properties etc to
49083  *  remain allocated.  This marking is only done for unreachable values which
49084  *  would be swept later.
49085  *
49086  *  Objects are first marked FINALIZABLE and only then marked as reachability
49087  *  roots; otherwise circular references might be handled inconsistently.
49088  */
49089
49090 #if defined(DUK_USE_FINALIZER_SUPPORT)
49091 DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
49092         duk_heaphdr *hdr;
49093         duk_size_t count_finalizable = 0;
49094
49095         DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap));
49096
49097         DUK_ASSERT(heap->heap_thread != NULL);
49098
49099         hdr = heap->heap_allocated;
49100         while (hdr != NULL) {
49101                 /* A finalizer is looked up from the object and up its
49102                  * prototype chain (which allows inherited finalizers).
49103                  * The finalizer is checked for using a duk_hobject flag
49104                  * which is kept in sync with the presence and callability
49105                  * of a _Finalizer hidden symbol.
49106                  */
49107
49108                 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
49109                     DUK_HEAPHDR_IS_OBJECT(hdr) &&
49110                     !DUK_HEAPHDR_HAS_FINALIZED(hdr) &&
49111                     DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr)) {
49112                         /* heaphdr:
49113                          *  - is not reachable
49114                          *  - is an object
49115                          *  - is not a finalized object waiting for rescue/keep decision
49116                          *  - has a finalizer
49117                          */
49118
49119                         DUK_DD(DUK_DDPRINT("unreachable heap object will be "
49120                                            "finalized -> mark as finalizable "
49121                                            "and treat as a reachability root: %p",
49122                                            (void *) hdr));
49123                         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
49124                         DUK_HEAPHDR_SET_FINALIZABLE(hdr);
49125                         count_finalizable++;
49126                 }
49127
49128                 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49129         }
49130
49131         if (count_finalizable == 0) {
49132                 return;
49133         }
49134
49135         DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable",
49136                            (long) count_finalizable));
49137
49138         hdr = heap->heap_allocated;
49139         while (hdr != NULL) {
49140                 if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
49141                         duk__mark_heaphdr_nonnull(heap, hdr);
49142                 }
49143
49144                 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49145         }
49146
49147         /* Caller will finish the marking process if we hit a recursion limit. */
49148 }
49149 #endif  /* DUK_USE_FINALIZER_SUPPORT */
49150
49151 /*
49152  *  Mark objects on finalize_list.
49153  */
49154
49155 #if defined(DUK_USE_FINALIZER_SUPPORT)
49156 DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
49157         duk_heaphdr *hdr;
49158 #if defined(DUK_USE_DEBUG)
49159         duk_size_t count_finalize_list = 0;
49160 #endif
49161
49162         DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap));
49163
49164         hdr = heap->finalize_list;
49165         while (hdr != NULL) {
49166                 duk__mark_heaphdr_nonnull(heap, hdr);
49167                 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49168 #if defined(DUK_USE_DEBUG)
49169                 count_finalize_list++;
49170 #endif
49171         }
49172
49173 #if defined(DUK_USE_DEBUG)
49174         if (count_finalize_list > 0) {
49175                 DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)",
49176                                  (long) count_finalize_list));
49177         }
49178 #endif
49179 }
49180 #endif  /* DUK_USE_FINALIZER_SUPPORT */
49181
49182 /*
49183  *  Fallback marking handler if recursion limit is reached.
49184  *
49185  *  Iterates 'temproots' until recursion limit is no longer hit.  Temproots
49186  *  can be in heap_allocated or finalize_list; refzero_list is now always
49187  *  empty for mark-and-sweep.  A temproot may occur in finalize_list now if
49188  *  there are objects on the finalize_list and user code creates a reference
49189  *  from an object in heap_allocated to the object in finalize_list (which is
49190  *  now allowed), and it happened to coincide with the recursion depth limit.
49191  *
49192  *  This is a slow scan, but guarantees that we finish with a bounded C stack.
49193  *
49194  *  Note that nodes may have been marked as temproots before this scan begun,
49195  *  OR they may have been marked during the scan (as we process nodes
49196  *  recursively also during the scan).  This is intended behavior.
49197  */
49198
49199 #if defined(DUK_USE_DEBUG)
49200 DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) {
49201 #else
49202 DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
49203 #endif
49204         DUK_ASSERT(hdr != NULL);
49205
49206         if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
49207                 DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
49208                 return;
49209         }
49210
49211         DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr));
49212         DUK_HEAPHDR_CLEAR_TEMPROOT(hdr);
49213         DUK_HEAPHDR_CLEAR_REACHABLE(hdr);  /* Done so that duk__mark_heaphdr() works correctly. */
49214 #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
49215         hdr->h_assert_refcount--;  /* Same node visited twice. */
49216 #endif
49217         duk__mark_heaphdr_nonnull(heap, hdr);
49218
49219 #if defined(DUK_USE_DEBUG)
49220         (*count)++;
49221 #endif
49222 }
49223
49224 DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
49225         duk_heaphdr *hdr;
49226 #if defined(DUK_USE_DEBUG)
49227         duk_size_t count;
49228 #endif
49229
49230         DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap));
49231
49232         while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) {
49233                 DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots"));
49234
49235 #if defined(DUK_USE_DEBUG)
49236                 count = 0;
49237 #endif
49238                 DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap);
49239
49240                 hdr = heap->heap_allocated;
49241                 while (hdr) {
49242 #if defined(DUK_USE_DEBUG)
49243                         duk__handle_temproot(heap, hdr, &count);
49244 #else
49245                         duk__handle_temproot(heap, hdr);
49246 #endif
49247                         hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49248                 }
49249
49250 #if defined(DUK_USE_FINALIZER_SUPPORT)
49251                 hdr = heap->finalize_list;
49252                 while (hdr) {
49253 #if defined(DUK_USE_DEBUG)
49254                         duk__handle_temproot(heap, hdr, &count);
49255 #else
49256                         duk__handle_temproot(heap, hdr);
49257 #endif
49258                         hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49259                 }
49260 #endif
49261
49262 #if defined(DUK_USE_DEBUG)
49263                 DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count));
49264 #endif
49265         }
49266 }
49267
49268 /*
49269  *  Finalize refcounts for heap elements just about to be freed.
49270  *  This must be done for all objects before freeing to avoid any
49271  *  stale pointer dereferences.
49272  *
49273  *  Note that this must deduce the set of objects to be freed
49274  *  identically to duk__sweep_heap().
49275  */
49276
49277 #if defined(DUK_USE_REFERENCE_COUNTING)
49278 DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
49279         duk_heaphdr *hdr;
49280
49281         DUK_ASSERT(heap->heap_thread != NULL);
49282
49283         DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p", (void *) heap));
49284
49285         hdr = heap->heap_allocated;
49286         while (hdr) {
49287                 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) {
49288                         /*
49289                          *  Unreachable object about to be swept.  Finalize target refcounts
49290                          *  (objects which the unreachable object points to) without doing
49291                          *  refzero processing.  Recursive decrefs are also prevented when
49292                          *  refzero processing is disabled.
49293                          *
49294                          *  Value cannot be a finalizable object, as they have been made
49295                          *  temporarily reachable for this round.
49296                          */
49297
49298                         DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
49299
49300                         /* Finalize using heap->heap_thread; DECREF has a
49301                          * suppress check for mark-and-sweep which is based
49302                          * on heap->ms_running.
49303                          */
49304                         duk_heaphdr_refcount_finalize_norz(heap, hdr);
49305                 }
49306
49307                 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49308         }
49309 }
49310 #endif  /* DUK_USE_REFERENCE_COUNTING */
49311
49312 /*
49313  *  Clear (reachable) flags of finalize_list.
49314  *
49315  *  We could mostly do in the sweep phase when we move objects from the
49316  *  heap into the finalize_list.  However, if a finalizer run is skipped
49317  *  during a mark-and-sweep, the objects on the finalize_list will be marked
49318  *  reachable during the next mark-and-sweep.  Since they're already on the
49319  *  finalize_list, no-one will be clearing their REACHABLE flag so we do it
49320  *  here.  (This now overlaps with the sweep handling in a harmless way.)
49321  */
49322
49323 #if defined(DUK_USE_FINALIZER_SUPPORT)
49324 DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
49325         duk_heaphdr *hdr;
49326
49327         DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap));
49328
49329         hdr = heap->finalize_list;
49330         while (hdr) {
49331                 DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
49332 #if defined(DUK_USE_ASSERTIONS)
49333                 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZABLE(hdr) || \
49334                            (heap->currently_finalizing == hdr));
49335 #endif
49336                 /* DUK_HEAPHDR_FLAG_FINALIZED may be set. */
49337                 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
49338                 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49339         }
49340 }
49341 #endif  /* DUK_USE_FINALIZER_SUPPORT */
49342
49343 /*
49344  *  Sweep stringtable.
49345  */
49346
49347 DUK_LOCAL void duk__sweep_stringtable(duk_heap *heap, duk_size_t *out_count_keep) {
49348         duk_hstring *h;
49349         duk_hstring *prev;
49350         duk_uint32_t i;
49351 #if defined(DUK_USE_DEBUG)
49352         duk_size_t count_free = 0;
49353 #endif
49354         duk_size_t count_keep = 0;
49355
49356         DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
49357
49358 #if defined(DUK_USE_STRTAB_PTRCOMP)
49359         if (heap->strtable16 == NULL) {
49360 #else
49361         if (heap->strtable == NULL) {
49362 #endif
49363                 goto done;
49364         }
49365
49366         for (i = 0; i < heap->st_size; i++) {
49367 #if defined(DUK_USE_STRTAB_PTRCOMP)
49368                 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
49369 #else
49370                 h = heap->strtable[i];
49371 #endif
49372                 prev = NULL;
49373                 while (h != NULL) {
49374                         duk_hstring *next;
49375                         next = h->hdr.h_next;
49376
49377                         if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h))
49378                         {
49379                                 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
49380                                 count_keep++;
49381                                 prev = h;
49382                         } else {
49383 #if defined(DUK_USE_DEBUG)
49384                                 count_free++;
49385 #endif
49386
49387                                 /* For pinned strings the refcount has been
49388                                  * bumped.  We could unbump it here before
49389                                  * freeing, but that's actually not necessary
49390                                  * except for assertions.
49391                                  */
49392 #if 0
49393                                 if (DUK_HSTRING_HAS_PINNED_LITERAL(h)) {
49394                                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) > 0U);
49395                                         DUK_HSTRING_DECREF_NORZ(heap->heap_thread, h);
49396                                         DUK_HSTRING_CLEAR_PINNED_LITERAL(h);
49397                                 }
49398 #endif
49399 #if defined(DUK_USE_REFERENCE_COUNTING)
49400                                 /* Non-zero refcounts should not happen for unreachable strings,
49401                                  * because we refcount finalize all unreachable objects which
49402                                  * should have decreased unreachable string refcounts to zero
49403                                  * (even for cycles).  However, pinned strings have a +1 bump.
49404                                  */
49405                                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) ==
49406                                            DUK_HSTRING_HAS_PINNED_LITERAL(h) ? 1U : 0U);
49407 #endif
49408
49409                                 /* Deal with weak references first. */
49410                                 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
49411
49412                                 /* Remove the string from the string table. */
49413                                 duk_heap_strtable_unlink_prev(heap, (duk_hstring *) h, (duk_hstring *) prev);
49414
49415                                 /* Free inner references (these exist e.g. when external
49416                                  * strings are enabled) and the struct itself.
49417                                  */
49418                                 duk_free_hstring(heap, (duk_hstring *) h);
49419
49420                                 /* Don't update 'prev'; it should be last string kept. */
49421                         }
49422
49423                         h = next;
49424                 }
49425         }
49426
49427  done:
49428 #if defined(DUK_USE_DEBUG)
49429         DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
49430                          (long) count_free, (long) count_keep));
49431 #endif
49432         *out_count_keep = count_keep;
49433 }
49434
49435 /*
49436  *  Sweep heap.
49437  */
49438
49439 DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_small_uint_t flags, duk_size_t *out_count_keep) {
49440         duk_heaphdr *prev;  /* last element that was left in the heap */
49441         duk_heaphdr *curr;
49442         duk_heaphdr *next;
49443 #if defined(DUK_USE_DEBUG)
49444         duk_size_t count_free = 0;
49445         duk_size_t count_finalize = 0;
49446         duk_size_t count_rescue = 0;
49447 #endif
49448         duk_size_t count_keep = 0;
49449
49450         DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
49451
49452         prev = NULL;
49453         curr = heap->heap_allocated;
49454         heap->heap_allocated = NULL;
49455         while (curr) {
49456                 /* Strings and ROM objects are never placed on the heap allocated list. */
49457                 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING);
49458                 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr));
49459
49460                 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
49461
49462                 if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
49463                         /*
49464                          *  Reachable object:
49465                          *    - If FINALIZABLE -> actually unreachable (but marked
49466                          *      artificially reachable), queue to finalize_list.
49467                          *    - If !FINALIZABLE but FINALIZED -> rescued after
49468                          *      finalizer execution.
49469                          *    - Otherwise just a normal, reachable object.
49470                          *
49471                          *  Objects which are kept are queued to heap_allocated
49472                          *  tail (we're essentially filtering heap_allocated in
49473                          *  practice).
49474                          */
49475
49476 #if defined(DUK_USE_FINALIZER_SUPPORT)
49477                         if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZABLE(curr))) {
49478                                 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
49479                                 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
49480                                 DUK_DD(DUK_DDPRINT("sweep; reachable, finalizable --> move to finalize_list: %p", (void *) curr));
49481
49482 #if defined(DUK_USE_REFERENCE_COUNTING)
49483                                 DUK_HEAPHDR_PREINC_REFCOUNT(curr);  /* Bump refcount so that refzero never occurs when pending a finalizer call. */
49484 #endif
49485                                 DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, curr);
49486 #if defined(DUK_USE_DEBUG)
49487                                 count_finalize++;
49488 #endif
49489                         }
49490                         else
49491 #endif  /* DUK_USE_FINALIZER_SUPPORT */
49492                         {
49493                                 if (DUK_UNLIKELY(DUK_HEAPHDR_HAS_FINALIZED(curr))) {
49494                                         DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
49495                                         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
49496
49497                                         if (flags & DUK_MS_FLAG_POSTPONE_RESCUE) {
49498                                                 DUK_DD(DUK_DDPRINT("sweep; reachable, finalized, but postponing rescue decisions --> keep object (with FINALIZED set): %!iO", curr));
49499                                                 count_keep++;
49500                                         } else {
49501                                                 DUK_DD(DUK_DDPRINT("sweep; reachable, finalized --> rescued after finalization: %p", (void *) curr));
49502 #if defined(DUK_USE_FINALIZER_SUPPORT)
49503                                                 DUK_HEAPHDR_CLEAR_FINALIZED(curr);
49504 #endif
49505 #if defined(DUK_USE_DEBUG)
49506                                                 count_rescue++;
49507 #endif
49508                                         }
49509                                 } else {
49510                                         DUK_DD(DUK_DDPRINT("sweep; reachable --> keep: %!iO", curr));
49511                                         count_keep++;
49512                                 }
49513
49514                                 if (prev != NULL) {
49515                                         DUK_ASSERT(heap->heap_allocated != NULL);
49516                                         DUK_HEAPHDR_SET_NEXT(heap, prev, curr);
49517                                 } else {
49518                                         DUK_ASSERT(heap->heap_allocated == NULL);
49519                                         heap->heap_allocated = curr;
49520                                 }
49521 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
49522                                 DUK_HEAPHDR_SET_PREV(heap, curr, prev);
49523 #endif
49524                                 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
49525                                 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
49526                                 prev = curr;
49527                         }
49528
49529                         /*
49530                          *  Shrink check for value stacks here.  We're inside
49531                          *  ms_prevent_count protection which prevents recursive
49532                          *  mark-and-sweep and refzero finalizers, so there are
49533                          *  no side effects that would affect the heap lists.
49534                          */
49535                         if (DUK_HEAPHDR_IS_OBJECT(curr) && DUK_HOBJECT_IS_THREAD((duk_hobject *) curr)) {
49536                                 duk_hthread *thr_curr = (duk_hthread *) curr;
49537                                 DUK_DD(DUK_DDPRINT("value stack shrink check for thread: %!O", curr));
49538                                 duk_valstack_shrink_check_nothrow(thr_curr, flags & DUK_MS_FLAG_EMERGENCY /*snug*/);
49539                         }
49540
49541                         DUK_HEAPHDR_CLEAR_REACHABLE(curr);
49542                         /* Keep FINALIZED if set, used if rescue decisions are postponed. */
49543                         /* Keep FINALIZABLE for objects on finalize_list. */
49544                         DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
49545                 } else {
49546                         /*
49547                          *  Unreachable object:
49548                          *    - If FINALIZED, object was finalized but not
49549                          *      rescued.  This doesn't affect freeing.
49550                          *    - Otherwise normal unreachable object.
49551                          *
49552                          *  There's no guard preventing a FINALIZED object
49553                          *  from being freed while finalizers execute: the
49554                          *  artificial finalize_list reachability roots can't
49555                          *  cause an incorrect free decision (but can cause
49556                          *  an incorrect rescue decision).
49557                          */
49558
49559 #if defined(DUK_USE_REFERENCE_COUNTING)
49560                         /* Non-zero refcounts should not happen because we refcount
49561                          * finalize all unreachable objects which should cancel out
49562                          * refcounts (even for cycles).
49563                          */
49564                         DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0);
49565 #endif
49566                         DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
49567
49568 #if defined(DUK_USE_DEBUG)
49569                         if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
49570                                 DUK_DD(DUK_DDPRINT("sweep; unreachable, finalized --> finalized object not rescued: %p", (void *) curr));
49571                         } else {
49572                                 DUK_DD(DUK_DDPRINT("sweep; not reachable --> free: %p", (void *) curr));
49573                         }
49574
49575 #endif
49576
49577                         /* Note: object cannot be a finalizable unreachable object, as
49578                          * they have been marked temporarily reachable for this round,
49579                          * and are handled above.
49580                          */
49581
49582 #if defined(DUK_USE_DEBUG)
49583                         count_free++;
49584 #endif
49585
49586                         /* Weak refs should be handled here, but no weak refs for
49587                          * any non-string objects exist right now.
49588                          */
49589
49590                         /* Free object and all auxiliary (non-heap) allocs. */
49591                         duk_heap_free_heaphdr_raw(heap, curr);
49592                 }
49593
49594                 curr = next;
49595         }
49596
49597         if (prev != NULL) {
49598                 DUK_HEAPHDR_SET_NEXT(heap, prev, NULL);
49599         }
49600         DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
49601
49602 #if defined(DUK_USE_DEBUG)
49603         DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization",
49604                          (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize));
49605 #endif
49606         *out_count_keep = count_keep;
49607 }
49608
49609 /*
49610  *  Litcache helpers.
49611  */
49612
49613 #if defined(DUK_USE_LITCACHE_SIZE)
49614 DUK_LOCAL void duk__wipe_litcache(duk_heap *heap) {
49615         duk_uint_t i;
49616         duk_litcache_entry *e;
49617
49618         e = heap->litcache;
49619         for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
49620                 e->addr = NULL;
49621                 /* e->h does not need to be invalidated: when e->addr is
49622                  * NULL, e->h is considered garbage.
49623                  */
49624                 e++;
49625         }
49626 }
49627 #endif  /* DUK_USE_LITCACHE_SIZE */
49628
49629 /*
49630  *  Object compaction.
49631  *
49632  *  Compaction is assumed to never throw an error.
49633  */
49634
49635 DUK_LOCAL int duk__protected_compact_object(duk_hthread *thr, void *udata) {
49636         duk_hobject *obj;
49637         /* XXX: for threads, compact stacks? */
49638
49639         DUK_UNREF(udata);
49640         obj = duk_known_hobject(thr, -1);
49641         duk_hobject_compact_props(thr, obj);
49642         return 0;
49643 }
49644
49645 #if defined(DUK_USE_DEBUG)
49646 DUK_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) {
49647 #else
49648 DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) {
49649 #endif
49650         duk_heaphdr *curr;
49651 #if defined(DUK_USE_DEBUG)
49652         duk_size_t old_size, new_size;
49653 #endif
49654         duk_hobject *obj;
49655
49656         DUK_UNREF(heap);
49657
49658         curr = start;
49659         while (curr) {
49660                 DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr));
49661
49662                 if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) {
49663                         goto next;
49664                 }
49665                 obj = (duk_hobject *) curr;
49666
49667 #if defined(DUK_USE_DEBUG)
49668                 old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
49669                                                       DUK_HOBJECT_GET_ASIZE(obj),
49670                                                       DUK_HOBJECT_GET_HSIZE(obj));
49671 #endif
49672
49673                 DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
49674                 duk_push_hobject(thr, obj);
49675                 /* XXX: disable error handlers for duration of compaction? */
49676                 duk_safe_call(thr, duk__protected_compact_object, NULL, 1, 0);
49677
49678 #if defined(DUK_USE_DEBUG)
49679                 new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
49680                                                       DUK_HOBJECT_GET_ASIZE(obj),
49681                                                       DUK_HOBJECT_GET_HSIZE(obj));
49682 #endif
49683
49684 #if defined(DUK_USE_DEBUG)
49685                 (*p_count_compact)++;
49686                 (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size);
49687 #endif
49688
49689          next:
49690                 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
49691 #if defined(DUK_USE_DEBUG)
49692                 (*p_count_check)++;
49693 #endif
49694         }
49695 }
49696
49697 DUK_LOCAL void duk__compact_objects(duk_heap *heap) {
49698         /* XXX: which lists should participate?  to be finalized? */
49699 #if defined(DUK_USE_DEBUG)
49700         duk_size_t count_check = 0;
49701         duk_size_t count_compact = 0;
49702         duk_size_t count_bytes_saved = 0;
49703 #endif
49704
49705         DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap));
49706
49707         DUK_ASSERT(heap->heap_thread != NULL);
49708
49709 #if defined(DUK_USE_DEBUG)
49710         duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
49711 #if defined(DUK_USE_FINALIZER_SUPPORT)
49712         duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
49713 #endif
49714 #else
49715         duk__compact_object_list(heap, heap->heap_thread, heap->heap_allocated);
49716 #if defined(DUK_USE_FINALIZER_SUPPORT)
49717         duk__compact_object_list(heap, heap->heap_thread, heap->finalize_list);
49718 #endif
49719 #endif
49720 #if defined(DUK_USE_REFERENCE_COUNTING)
49721         DUK_ASSERT(heap->refzero_list == NULL);  /* Always handled to completion inline in DECREF. */
49722 #endif
49723
49724 #if defined(DUK_USE_DEBUG)
49725         DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction",
49726                          (long) count_check, (long) count_compact, (long) count_bytes_saved));
49727 #endif
49728 }
49729
49730 /*
49731  *  Assertion helpers.
49732  */
49733
49734 #if defined(DUK_USE_ASSERTIONS)
49735 DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) {
49736         duk_heaphdr *hdr;
49737
49738         hdr = heap->heap_allocated;
49739         while (hdr) {
49740                 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
49741                 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
49742                 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
49743                 /* may have FINALIZED */
49744                 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49745         }
49746
49747 #if defined(DUK_USE_REFERENCE_COUNTING)
49748         DUK_ASSERT(heap->refzero_list == NULL);  /* Always handled to completion inline in DECREF. */
49749 #endif
49750 }
49751
49752 #if defined(DUK_USE_REFERENCE_COUNTING)
49753 DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) {
49754         duk_heaphdr *hdr = heap->heap_allocated;
49755         while (hdr) {
49756                 /* Cannot really assert much w.r.t. refcounts now. */
49757
49758                 if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 &&
49759                     DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
49760                         /* An object may be in heap_allocated list with a zero
49761                          * refcount if it has just been finalized and is waiting
49762                          * to be collected by the next cycle.
49763                          * (This doesn't currently happen however.)
49764                          */
49765                 } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) {
49766                         /* An object may be in heap_allocated list with a zero
49767                          * refcount also if it is a temporary object created
49768                          * during debugger paused state.  It will get collected
49769                          * by mark-and-sweep based on its reachability status
49770                          * (presumably not reachable because refcount is 0).
49771                          */
49772                 }
49773                 DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(hdr) >= 0);  /* Unsigned. */
49774                 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
49775         }
49776 }
49777
49778 DUK_LOCAL void duk__clear_assert_refcounts(duk_heap *heap) {
49779         duk_heaphdr *curr;
49780         duk_uint32_t i;
49781
49782         for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
49783                 curr->h_assert_refcount = 0;
49784         }
49785 #if defined(DUK_USE_FINALIZER_SUPPORT)
49786         for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
49787                 curr->h_assert_refcount = 0;
49788         }
49789 #endif
49790 #if defined(DUK_USE_REFERENCE_COUNTING)
49791         for (curr = heap->refzero_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
49792                 curr->h_assert_refcount = 0;
49793         }
49794 #endif
49795
49796         for (i = 0; i < heap->st_size; i++) {
49797                 duk_hstring *h;
49798
49799 #if defined(DUK_USE_STRTAB_PTRCOMP)
49800                 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
49801 #else
49802                 h = heap->strtable[i];
49803 #endif
49804                 while (h != NULL) {
49805                         ((duk_heaphdr *) h)->h_assert_refcount = 0;
49806                         h = h->hdr.h_next;
49807                 }
49808         }
49809 }
49810
49811 DUK_LOCAL void duk__check_refcount_heaphdr(duk_heaphdr *hdr) {
49812         duk_bool_t count_ok;
49813         duk_size_t expect_refc;
49814
49815         /* The refcount check only makes sense for reachable objects on
49816          * heap_allocated or string table, after the sweep phase.  Prior to
49817          * sweep phase refcounts will include references that are not visible
49818          * via reachability roots.
49819          *
49820          * Because we're called after the sweep phase, all heap objects on
49821          * heap_allocated are reachable.  REACHABLE flags have already been
49822          * cleared so we can't check them.
49823          */
49824
49825         /* ROM objects have intentionally incorrect refcount (1), but we won't
49826          * check them.
49827          */
49828         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
49829
49830         expect_refc = hdr->h_assert_refcount;
49831         if (DUK_HEAPHDR_IS_STRING(hdr) && DUK_HSTRING_HAS_PINNED_LITERAL((duk_hstring *) hdr)) {
49832                 expect_refc++;
49833         }
49834         count_ok = ((duk_size_t) DUK_HEAPHDR_GET_REFCOUNT(hdr) == expect_refc);
49835         if (!count_ok) {
49836                 DUK_D(DUK_DPRINT("refcount mismatch for: %p: header=%ld counted=%ld --> %!iO",
49837                                  (void *) hdr, (long) DUK_HEAPHDR_GET_REFCOUNT(hdr),
49838                                  (long) hdr->h_assert_refcount, hdr));
49839                 DUK_ASSERT(0);
49840         }
49841 }
49842
49843 DUK_LOCAL void duk__check_assert_refcounts(duk_heap *heap) {
49844         duk_heaphdr *curr;
49845         duk_uint32_t i;
49846
49847         for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
49848                 duk__check_refcount_heaphdr(curr);
49849         }
49850 #if defined(DUK_USE_FINALIZER_SUPPORT)
49851         for (curr = heap->finalize_list; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
49852                 duk__check_refcount_heaphdr(curr);
49853         }
49854 #endif
49855
49856         for (i = 0; i < heap->st_size; i++) {
49857                 duk_hstring *h;
49858
49859 #if defined(DUK_USE_STRTAB_PTRCOMP)
49860                 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
49861 #else
49862                 h = heap->strtable[i];
49863 #endif
49864                 while (h != NULL) {
49865                         duk__check_refcount_heaphdr((duk_heaphdr *) h);
49866                         h = h->hdr.h_next;
49867                 }
49868         }
49869 }
49870 #endif  /* DUK_USE_REFERENCE_COUNTING */
49871
49872 #if defined(DUK_USE_LITCACHE_SIZE)
49873 DUK_LOCAL void duk__assert_litcache_nulls(duk_heap *heap) {
49874         duk_uint_t i;
49875         duk_litcache_entry *e;
49876
49877         e = heap->litcache;
49878         for (i = 0; i < DUK_USE_LITCACHE_SIZE; i++) {
49879                 /* Entry addresses were NULLed before mark-and-sweep, check
49880                  * that they're still NULL afterwards to ensure no pointers
49881                  * were recorded through any side effects.
49882                  */
49883                 DUK_ASSERT(e->addr == NULL);
49884         }
49885 }
49886 #endif  /* DUK_USE_LITCACHE_SIZE */
49887 #endif  /* DUK_USE_ASSERTIONS */
49888
49889 /*
49890  *  Stats dump.
49891  */
49892
49893 #if defined(DUK_USE_DEBUG)
49894 DUK_LOCAL void duk__dump_stats(duk_heap *heap) {
49895         DUK_D(DUK_DPRINT("stats executor: opcodes=%ld, interrupt=%ld, throw=%ld",
49896                          (long) heap->stats_exec_opcodes, (long) heap->stats_exec_interrupt,
49897                          (long) heap->stats_exec_throw));
49898         DUK_D(DUK_DPRINT("stats call: all=%ld, tailcall=%ld, ecmatoecma=%ld",
49899                          (long) heap->stats_call_all, (long) heap->stats_call_tailcall,
49900                          (long) heap->stats_call_ecmatoecma));
49901         DUK_D(DUK_DPRINT("stats safecall: all=%ld, nothrow=%ld, throw=%ld",
49902                          (long) heap->stats_safecall_all, (long) heap->stats_safecall_nothrow,
49903                          (long) heap->stats_safecall_throw));
49904         DUK_D(DUK_DPRINT("stats mark-and-sweep: try_count=%ld, skip_count=%ld, emergency_count=%ld",
49905                          (long) heap->stats_ms_try_count, (long) heap->stats_ms_skip_count,
49906                          (long) heap->stats_ms_emergency_count));
49907         DUK_D(DUK_DPRINT("stats stringtable: intern_hit=%ld, intern_miss=%ld, "
49908                          "resize_check=%ld, resize_grow=%ld, resize_shrink=%ld, "
49909                          "litcache_hit=%ld, litcache_miss=%ld, litcache_pin=%ld",
49910                          (long) heap->stats_strtab_intern_hit, (long) heap->stats_strtab_intern_miss,
49911                          (long) heap->stats_strtab_resize_check, (long) heap->stats_strtab_resize_grow,
49912                          (long) heap->stats_strtab_resize_shrink, (long) heap->stats_strtab_litcache_hit,
49913                          (long) heap->stats_strtab_litcache_miss, (long) heap->stats_strtab_litcache_pin));
49914         DUK_D(DUK_DPRINT("stats object: realloc_props=%ld, abandon_array=%ld",
49915                          (long) heap->stats_object_realloc_props, (long) heap->stats_object_abandon_array));
49916         DUK_D(DUK_DPRINT("stats getownpropdesc: count=%ld, hit=%ld, miss=%ld",
49917                          (long) heap->stats_getownpropdesc_count, (long) heap->stats_getownpropdesc_hit,
49918                          (long) heap->stats_getownpropdesc_miss));
49919         DUK_D(DUK_DPRINT("stats getpropdesc: count=%ld, hit=%ld, miss=%ld",
49920                          (long) heap->stats_getpropdesc_count, (long) heap->stats_getpropdesc_hit,
49921                          (long) heap->stats_getpropdesc_miss));
49922         DUK_D(DUK_DPRINT("stats getprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, "
49923                          "bufferidx=%ld, bufferlen=%ld, stringidx=%ld, stringlen=%ld, "
49924                          "proxy=%ld, arguments=%ld",
49925                          (long) heap->stats_getprop_all, (long) heap->stats_getprop_arrayidx,
49926                          (long) heap->stats_getprop_bufobjidx, (long) heap->stats_getprop_bufferidx,
49927                          (long) heap->stats_getprop_bufferlen, (long) heap->stats_getprop_stringidx,
49928                          (long) heap->stats_getprop_stringlen, (long) heap->stats_getprop_proxy,
49929                          (long) heap->stats_getprop_arguments));
49930         DUK_D(DUK_DPRINT("stats putprop: all=%ld, arrayidx=%ld, bufobjidx=%ld, "
49931                          "bufferidx=%ld, proxy=%ld",
49932                          (long) heap->stats_putprop_all, (long) heap->stats_putprop_arrayidx,
49933                          (long) heap->stats_putprop_bufobjidx, (long) heap->stats_putprop_bufferidx,
49934                          (long) heap->stats_putprop_proxy));
49935         DUK_D(DUK_DPRINT("stats getvar: all=%ld",
49936                          (long) heap->stats_getvar_all));
49937         DUK_D(DUK_DPRINT("stats putvar: all=%ld",
49938                          (long) heap->stats_putvar_all));
49939 }
49940 #endif  /* DUK_USE_DEBUG */
49941
49942 /*
49943  *  Main mark-and-sweep function.
49944  *
49945  *  'flags' represents the features requested by the caller.  The current
49946  *  heap->ms_base_flags is ORed automatically into the flags; the base flags
49947  *  mask typically prevents certain mark-and-sweep operation to avoid trouble.
49948  */
49949
49950 DUK_INTERNAL void duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) {
49951         duk_size_t count_keep_obj;
49952         duk_size_t count_keep_str;
49953 #if defined(DUK_USE_VOLUNTARY_GC)
49954         duk_size_t tmp;
49955 #endif
49956
49957         DUK_STATS_INC(heap, stats_ms_try_count);
49958 #if defined(DUK_USE_DEBUG)
49959         if (flags & DUK_MS_FLAG_EMERGENCY) {
49960                 DUK_STATS_INC(heap, stats_ms_emergency_count);
49961         }
49962 #endif
49963
49964         /* If debugger is paused, garbage collection is disabled by default.
49965          * This is achieved by bumping ms_prevent_count when becoming paused.
49966          */
49967         DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) || heap->ms_prevent_count > 0);
49968
49969         /* Prevention/recursion check as soon as possible because we may
49970          * be called a number of times when voluntary mark-and-sweep is
49971          * pending.
49972          */
49973         if (heap->ms_prevent_count != 0) {
49974                 DUK_DD(DUK_DDPRINT("reject recursive mark-and-sweep"));
49975                 DUK_STATS_INC(heap, stats_ms_skip_count);
49976                 return;
49977         }
49978         DUK_ASSERT(heap->ms_running == 0);  /* ms_prevent_count is bumped when ms_running is set */
49979
49980         /* Heap_thread is used during mark-and-sweep for refcount finalization
49981          * (it's also used for finalizer execution once mark-and-sweep is
49982          * complete).  Heap allocation code ensures heap_thread is set and
49983          * properly initialized before setting ms_prevent_count to 0.
49984          */
49985         DUK_ASSERT(heap->heap_thread != NULL);
49986         DUK_ASSERT(heap->heap_thread->valstack != NULL);
49987
49988         DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
49989                          (unsigned long) flags, (unsigned long) (flags | heap->ms_base_flags)));
49990
49991         flags |= heap->ms_base_flags;
49992 #if defined(DUK_USE_FINALIZER_SUPPORT)
49993         if (heap->finalize_list != NULL) {
49994                 flags |= DUK_MS_FLAG_POSTPONE_RESCUE;
49995         }
49996 #endif
49997
49998         /*
49999          *  Assertions before
50000          */
50001
50002 #if defined(DUK_USE_ASSERTIONS)
50003         DUK_ASSERT(heap->ms_prevent_count == 0);
50004         DUK_ASSERT(heap->ms_running == 0);
50005         DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(heap));
50006         DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
50007         DUK_ASSERT(heap->ms_recursion_depth == 0);
50008         duk__assert_heaphdr_flags(heap);
50009 #if defined(DUK_USE_REFERENCE_COUNTING)
50010         /* Note: heap->refzero_free_running may be true; a refcount
50011          * finalizer may trigger a mark-and-sweep.
50012          */
50013         duk__assert_valid_refcounts(heap);
50014 #endif  /* DUK_USE_REFERENCE_COUNTING */
50015 #endif  /* DUK_USE_ASSERTIONS */
50016
50017         /*
50018          *  Begin
50019          */
50020
50021         DUK_ASSERT(heap->ms_prevent_count == 0);
50022         DUK_ASSERT(heap->ms_running == 0);
50023         heap->ms_prevent_count = 1;
50024         heap->ms_running = 1;
50025
50026         /*
50027          *  Free activation/catcher freelists on every mark-and-sweep for now.
50028          *  This is an initial rough draft; ideally we'd keep count of the
50029          *  freelist size and free only excess entries.
50030          */
50031
50032         DUK_D(DUK_DPRINT("freeing temporary freelists"));
50033         duk_heap_free_freelists(heap);
50034
50035         /*
50036          *  Mark roots, hoping that recursion limit is not normally hit.
50037          *  If recursion limit is hit, run additional reachability rounds
50038          *  starting from "temproots" until marking is complete.
50039          *
50040          *  Marking happens in two phases: first we mark actual reachability
50041          *  roots (and run "temproots" to complete the process).  Then we
50042          *  check which objects are unreachable and are finalizable; such
50043          *  objects are marked as FINALIZABLE and marked as reachability
50044          *  (and "temproots" is run again to complete the process).
50045          *
50046          *  The heap finalize_list must also be marked as a reachability root.
50047          *  There may be objects on the list from a previous round if the
50048          *  previous run had finalizer skip flag.
50049          */
50050
50051 #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
50052         duk__clear_assert_refcounts(heap);
50053 #endif
50054 #if defined(DUK_USE_LITCACHE_SIZE)
50055         duk__wipe_litcache(heap);
50056 #endif
50057         duk__mark_roots_heap(heap);               /* Mark main reachability roots. */
50058 #if defined(DUK_USE_REFERENCE_COUNTING)
50059         DUK_ASSERT(heap->refzero_list == NULL);   /* Always handled to completion inline in DECREF. */
50060 #endif
50061         duk__mark_temproots_by_heap_scan(heap);   /* Temproots. */
50062
50063 #if defined(DUK_USE_FINALIZER_SUPPORT)
50064         duk__mark_finalizable(heap);              /* Mark finalizable as reachability roots. */
50065         duk__mark_finalize_list(heap);            /* Mark finalizer work list as reachability roots. */
50066 #endif
50067         duk__mark_temproots_by_heap_scan(heap);   /* Temproots. */
50068
50069         /*
50070          *  Sweep garbage and remove marking flags, and move objects with
50071          *  finalizers to the finalizer work list.
50072          *
50073          *  Objects to be swept need to get their refcounts finalized before
50074          *  they are swept.  In other words, their target object refcounts
50075          *  need to be decreased.  This has to be done before freeing any
50076          *  objects to avoid decref'ing dangling pointers (which may happen
50077          *  even without bugs, e.g. with reference loops)
50078          *
50079          *  Because strings don't point to other heap objects, similar
50080          *  finalization is not necessary for strings.
50081          */
50082
50083         /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
50084
50085 #if defined(DUK_USE_REFERENCE_COUNTING)
50086         duk__finalize_refcounts(heap);
50087 #endif
50088         duk__sweep_heap(heap, flags, &count_keep_obj);
50089         duk__sweep_stringtable(heap, &count_keep_str);
50090 #if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
50091         duk__check_assert_refcounts(heap);
50092 #endif
50093 #if defined(DUK_USE_REFERENCE_COUNTING)
50094         DUK_ASSERT(heap->refzero_list == NULL);   /* Always handled to completion inline in DECREF. */
50095 #endif
50096 #if defined(DUK_USE_FINALIZER_SUPPORT)
50097         duk__clear_finalize_list_flags(heap);
50098 #endif
50099
50100         /*
50101          *  Object compaction (emergency only).
50102          *
50103          *  Object compaction is a separate step after sweeping, as there is
50104          *  more free memory for it to work with.  Also, currently compaction
50105          *  may insert new objects into the heap allocated list and the string
50106          *  table which we don't want to do during a sweep (the reachability
50107          *  flags of such objects would be incorrect).  The objects inserted
50108          *  are currently:
50109          *
50110          *    - a temporary duk_hbuffer for a new properties allocation
50111          *    - if array part is abandoned, string keys are interned
50112          *
50113          *  The object insertions go to the front of the list, so they do not
50114          *  cause an infinite loop (they are not compacted).
50115          */
50116
50117         if ((flags & DUK_MS_FLAG_EMERGENCY) &&
50118             !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) {
50119                 duk__compact_objects(heap);
50120         }
50121
50122         /*
50123          *  String table resize check.
50124          *
50125          *  This is mainly useful in emergency GC: if the string table load
50126          *  factor is really low for some reason, we can shrink the string
50127          *  table to a smaller size and free some memory in the process.
50128          *  Only execute in emergency GC.  String table has internal flags
50129          *  to protect against recursive resizing if this mark-and-sweep pass
50130          *  was triggered by a string table resize.
50131          */
50132
50133         if (flags & DUK_MS_FLAG_EMERGENCY) {
50134                 DUK_D(DUK_DPRINT("stringtable resize check in emergency gc"));
50135                 duk_heap_strtable_force_resize(heap);
50136         }
50137
50138         /*
50139          *  Finish
50140          */
50141
50142         DUK_ASSERT(heap->ms_prevent_count == 1);
50143         heap->ms_prevent_count = 0;
50144         DUK_ASSERT(heap->ms_running == 1);
50145         heap->ms_running = 0;
50146
50147         /*
50148          *  Assertions after
50149          */
50150
50151 #if defined(DUK_USE_ASSERTIONS)
50152         DUK_ASSERT(heap->ms_prevent_count == 0);
50153         DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
50154         DUK_ASSERT(heap->ms_recursion_depth == 0);
50155         duk__assert_heaphdr_flags(heap);
50156 #if defined(DUK_USE_REFERENCE_COUNTING)
50157         /* Note: heap->refzero_free_running may be true; a refcount
50158          * finalizer may trigger a mark-and-sweep.
50159          */
50160         duk__assert_valid_refcounts(heap);
50161 #endif  /* DUK_USE_REFERENCE_COUNTING */
50162 #if defined(DUK_USE_LITCACHE_SIZE)
50163         duk__assert_litcache_nulls(heap);
50164 #endif  /* DUK_USE_LITCACHE_SIZE */
50165 #endif  /* DUK_USE_ASSERTIONS */
50166
50167         /*
50168          *  Reset trigger counter
50169          */
50170
50171 #if defined(DUK_USE_VOLUNTARY_GC)
50172         tmp = (count_keep_obj + count_keep_str) / 256;
50173         heap->ms_trigger_counter = (duk_int_t) (
50174             (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) +
50175             DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD);
50176         DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld",
50177                          (long) count_keep_obj, (long) count_keep_str, (long) heap->ms_trigger_counter));
50178 #else
50179         DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger",
50180                          (long) count_keep_obj, (long) count_keep_str));
50181 #endif
50182
50183         /*
50184          *  Stats dump
50185          */
50186
50187 #if defined(DUK_USE_DEBUG)
50188         duk__dump_stats(heap);
50189 #endif
50190
50191         /*
50192          *  Finalize objects in the finalization work list.  Finalized
50193          *  objects are queued back to heap_allocated with FINALIZED set.
50194          *
50195          *  Since finalizers may cause arbitrary side effects, they are
50196          *  prevented e.g. during string table and object property allocation
50197          *  resizing using heap->pf_prevent_count.  In this case the objects
50198          *  remain in the finalization work list after mark-and-sweep exits
50199          *  and they may be finalized on the next pass or any DECREF checking
50200          *  for finalize_list.
50201          *
50202          *  As of Duktape 2.1 finalization happens outside mark-and-sweep
50203          *  protection.  Mark-and-sweep is allowed while the finalize_list
50204          *  is being processed, but no rescue decisions are done while the
50205          *  process is on-going.  This avoids incorrect rescue decisions
50206          *  if an object is considered reachable (and thus rescued) because
50207          *  of a reference via finalize_list (which is considered a reachability
50208          *  root).  When finalize_list is being processed, reachable objects
50209          *  with FINALIZED set will just keep their FINALIZED flag for later
50210          *  mark-and-sweep processing.
50211          *
50212          *  This could also be handled (a bit better) by having a more refined
50213          *  notion of reachability for rescue/free decisions.
50214          *
50215          *  XXX: avoid finalizer execution when doing emergency GC?
50216          */
50217
50218 #if defined(DUK_USE_FINALIZER_SUPPORT)
50219         /* Attempt to process finalize_list, pf_prevent_count check
50220          * is inside the target.
50221          */
50222         duk_heap_process_finalize_list(heap);
50223 #endif  /* DUK_USE_FINALIZER_SUPPORT */
50224 }
50225 #line 1 "duk_heap_memory.c"
50226 /*
50227  *  Memory allocation handling.
50228  */
50229
50230 /* #include duk_internal.h -> already included */
50231
50232 /*
50233  *  Voluntary GC check
50234  */
50235
50236 #if defined(DUK_USE_VOLUNTARY_GC)
50237 DUK_LOCAL DUK_INLINE void duk__check_voluntary_gc(duk_heap *heap) {
50238         if (DUK_UNLIKELY(--(heap)->ms_trigger_counter < 0)) {
50239 #if defined(DUK_USE_DEBUG)
50240                 if (heap->ms_prevent_count == 0) {
50241                         DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep"));
50242                 } else {
50243                         DUK_DD(DUK_DDPRINT("gc blocked -> skip voluntary mark-and-sweep now"));
50244                 }
50245 #endif
50246
50247                 /* Prevention checks in the call target handle cases where
50248                  * voluntary GC is not allowed.  The voluntary GC trigger
50249                  * counter is only rewritten if mark-and-sweep actually runs.
50250                  */
50251                 duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_VOLUNTARY /*flags*/);
50252         }
50253 }
50254 #define DUK__VOLUNTARY_PERIODIC_GC(heap)  do { duk__check_voluntary_gc((heap)); } while (0)
50255 #else
50256 #define DUK__VOLUNTARY_PERIODIC_GC(heap)  /* no voluntary gc */
50257 #endif  /* DUK_USE_VOLUNTARY_GC */
50258
50259 /*
50260  *  Allocate memory with garbage collection
50261  */
50262
50263 DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
50264         void *res;
50265         duk_small_int_t i;
50266
50267         DUK_ASSERT(heap != NULL);
50268         DUK_ASSERT_DISABLE(size >= 0);
50269
50270         /*
50271          *  Voluntary periodic GC (if enabled)
50272          */
50273
50274         DUK__VOLUNTARY_PERIODIC_GC(heap);
50275
50276         /*
50277          *  First attempt
50278          */
50279
50280 #if defined(DUK_USE_GC_TORTURE)
50281         /* Simulate alloc failure on every alloc, except when mark-and-sweep
50282          * is running.
50283          */
50284         if (heap->ms_prevent_count == 0) {
50285                 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
50286                 res = NULL;
50287                 DUK_UNREF(res);
50288                 goto skip_attempt;
50289         }
50290 #endif
50291         res = heap->alloc_func(heap->heap_udata, size);
50292         if (DUK_LIKELY(res || size == 0)) {
50293                 /* For zero size allocations NULL is allowed. */
50294                 return res;
50295         }
50296 #if defined(DUK_USE_GC_TORTURE)
50297  skip_attempt:
50298 #endif
50299
50300         DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry"));
50301
50302 #if 0
50303         /*
50304          *  Avoid a GC if GC is already running.  This can happen at a late
50305          *  stage in a GC when we try to e.g. resize the stringtable
50306          *  or compact objects.
50307          *
50308          *  NOTE: explicit handling isn't actually be needed: if the GC is
50309          *  not allowed, duk_heap_mark_and_sweep() will reject it for every
50310          *  attempt in the loop below, resulting in a NULL same as here.
50311          */
50312
50313         if (heap->ms_prevent_count != 0) {
50314                 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size));
50315                 return NULL;
50316         }
50317 #endif
50318
50319         /*
50320          *  Retry with several GC attempts.  Initial attempts are made without
50321          *  emergency mode; later attempts use emergency mode which minimizes
50322          *  memory allocations forcibly.
50323          */
50324
50325         for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
50326                 duk_small_uint_t flags;
50327
50328                 flags = 0;
50329                 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
50330                         flags |= DUK_MS_FLAG_EMERGENCY;
50331                 }
50332
50333                 duk_heap_mark_and_sweep(heap, flags);
50334
50335                 res = heap->alloc_func(heap->heap_udata, size);
50336                 if (res) {
50337                         DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld",
50338                                          (long) (i + 1), (long) size));
50339                         return res;
50340                 }
50341         }
50342
50343         DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size));
50344         return NULL;
50345 }
50346
50347 DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
50348         void *res;
50349
50350         DUK_ASSERT(heap != NULL);
50351         DUK_ASSERT_DISABLE(size >= 0);
50352
50353         res = DUK_ALLOC(heap, size);
50354         if (DUK_LIKELY(res != NULL)) {
50355                 duk_memzero(res, size);
50356         }
50357         return res;
50358 }
50359
50360 DUK_INTERNAL void *duk_heap_mem_alloc_checked(duk_hthread *thr, duk_size_t size) {
50361         void *res;
50362
50363         DUK_ASSERT(thr != NULL);
50364         res = duk_heap_mem_alloc(thr->heap, size);
50365         if (DUK_LIKELY(res != NULL || size == 0)) {
50366                 return res;
50367         }
50368         DUK_ERROR_ALLOC_FAILED(thr);
50369         DUK_WO_NORETURN(return NULL;);
50370 }
50371
50372 DUK_INTERNAL void *duk_heap_mem_alloc_checked_zeroed(duk_hthread *thr, duk_size_t size) {
50373         void *res;
50374
50375         DUK_ASSERT(thr != NULL);
50376         res = duk_heap_mem_alloc_zeroed(thr->heap, size);
50377         if (DUK_LIKELY(res != NULL || size == 0)) {
50378                 return res;
50379         }
50380         DUK_ERROR_ALLOC_FAILED(thr);
50381         DUK_WO_NORETURN(return NULL;);
50382 }
50383
50384 /*
50385  *  Reallocate memory with garbage collection
50386  */
50387
50388 DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
50389         void *res;
50390         duk_small_int_t i;
50391
50392         DUK_ASSERT(heap != NULL);
50393         /* ptr may be NULL */
50394         DUK_ASSERT_DISABLE(newsize >= 0);
50395
50396         /*
50397          *  Voluntary periodic GC (if enabled)
50398          */
50399
50400         DUK__VOLUNTARY_PERIODIC_GC(heap);
50401
50402         /*
50403          *  First attempt
50404          */
50405
50406 #if defined(DUK_USE_GC_TORTURE)
50407         /* Simulate alloc failure on every realloc, except when mark-and-sweep
50408          * is running.
50409          */
50410         if (heap->ms_prevent_count == 0) {
50411                 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails"));
50412                 res = NULL;
50413                 DUK_UNREF(res);
50414                 goto skip_attempt;
50415         }
50416 #endif
50417         res = heap->realloc_func(heap->heap_udata, ptr, newsize);
50418         if (DUK_LIKELY(res || newsize == 0)) {
50419                 /* For zero size allocations NULL is allowed. */
50420                 return res;
50421         }
50422 #if defined(DUK_USE_GC_TORTURE)
50423  skip_attempt:
50424 #endif
50425
50426         DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
50427
50428 #if 0
50429         /*
50430          *  Avoid a GC if GC is already running.  See duk_heap_mem_alloc().
50431          */
50432
50433         if (heap->ms_prevent_count != 0) {
50434                 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
50435                 return NULL;
50436         }
50437 #endif
50438
50439         /*
50440          *  Retry with several GC attempts.  Initial attempts are made without
50441          *  emergency mode; later attempts use emergency mode which minimizes
50442          *  memory allocations forcibly.
50443          */
50444
50445         for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
50446                 duk_small_uint_t flags;
50447
50448                 flags = 0;
50449                 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
50450                         flags |= DUK_MS_FLAG_EMERGENCY;
50451                 }
50452
50453                 duk_heap_mark_and_sweep(heap, flags);
50454
50455                 res = heap->realloc_func(heap->heap_udata, ptr, newsize);
50456                 if (res || newsize == 0) {
50457                         DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld",
50458                                          (long) (i + 1), (long) newsize));
50459                         return res;
50460                 }
50461         }
50462
50463         DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize));
50464         return NULL;
50465 }
50466
50467 /*
50468  *  Reallocate memory with garbage collection, using a callback to provide
50469  *  the current allocated pointer.  This variant is used when a mark-and-sweep
50470  *  (e.g. finalizers) might change the original pointer.
50471  */
50472
50473 DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
50474         void *res;
50475         duk_small_int_t i;
50476
50477         DUK_ASSERT(heap != NULL);
50478         DUK_ASSERT_DISABLE(newsize >= 0);
50479
50480         /*
50481          *  Voluntary periodic GC (if enabled)
50482          */
50483
50484         DUK__VOLUNTARY_PERIODIC_GC(heap);
50485
50486         /*
50487          *  First attempt
50488          */
50489
50490 #if defined(DUK_USE_GC_TORTURE)
50491         /* Simulate alloc failure on every realloc, except when mark-and-sweep
50492          * is running.
50493          */
50494         if (heap->ms_prevent_count == 0) {
50495                 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
50496                 res = NULL;
50497                 DUK_UNREF(res);
50498                 goto skip_attempt;
50499         }
50500 #endif
50501         res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
50502         if (DUK_LIKELY(res || newsize == 0)) {
50503                 /* For zero size allocations NULL is allowed. */
50504                 return res;
50505         }
50506 #if defined(DUK_USE_GC_TORTURE)
50507  skip_attempt:
50508 #endif
50509
50510         DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
50511
50512 #if 0
50513         /*
50514          *  Avoid a GC if GC is already running.  See duk_heap_mem_alloc().
50515          */
50516
50517         if (heap->ms_prevent_count != 0) {
50518                 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
50519                 return NULL;
50520         }
50521 #endif
50522
50523         /*
50524          *  Retry with several GC attempts.  Initial attempts are made without
50525          *  emergency mode; later attempts use emergency mode which minimizes
50526          *  memory allocations forcibly.
50527          */
50528
50529         for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
50530                 duk_small_uint_t flags;
50531
50532 #if defined(DUK_USE_DEBUG)
50533                 void *ptr_pre;
50534                 void *ptr_post;
50535 #endif
50536
50537 #if defined(DUK_USE_DEBUG)
50538                 ptr_pre = cb(heap, ud);
50539 #endif
50540                 flags = 0;
50541                 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
50542                         flags |= DUK_MS_FLAG_EMERGENCY;
50543                 }
50544
50545                 duk_heap_mark_and_sweep(heap, flags);
50546 #if defined(DUK_USE_DEBUG)
50547                 ptr_post = cb(heap, ud);
50548                 if (ptr_pre != ptr_post) {
50549                         DUK_DD(DUK_DDPRINT("realloc base pointer changed by mark-and-sweep: %p -> %p",
50550                                            (void *) ptr_pre, (void *) ptr_post));
50551                 }
50552 #endif
50553
50554                 /* Note: key issue here is to re-lookup the base pointer on every attempt.
50555                  * The pointer being reallocated may change after every mark-and-sweep.
50556                  */
50557
50558                 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
50559                 if (res || newsize == 0) {
50560                         DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld",
50561                                          (long) (i + 1), (long) newsize));
50562                         return res;
50563                 }
50564         }
50565
50566         DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize));
50567         return NULL;
50568 }
50569
50570 /*
50571  *  Free memory
50572  */
50573
50574 DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
50575         DUK_ASSERT(heap != NULL);
50576         /* ptr may be NULL */
50577
50578         /* Must behave like a no-op with NULL and any pointer returned from
50579          * malloc/realloc with zero size.
50580          */
50581         heap->free_func(heap->heap_udata, ptr);
50582
50583         /* Never perform a GC (even voluntary) in a memory free, otherwise
50584          * all call sites doing frees would need to deal with the side effects.
50585          * No need to update voluntary GC counter either.
50586          */
50587 }
50588
50589 /* automatic undefs */
50590 #undef DUK__VOLUNTARY_PERIODIC_GC
50591 #line 1 "duk_heap_misc.c"
50592 /*
50593  *  Support functions for duk_heap.
50594  */
50595
50596 /* #include duk_internal.h -> already included */
50597
50598 DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
50599         duk_heaphdr *root;
50600
50601         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
50602
50603         root = heap->heap_allocated;
50604 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
50605         if (root != NULL) {
50606                 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
50607                 DUK_HEAPHDR_SET_PREV(heap, root, hdr);
50608         }
50609         DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
50610 #endif
50611         DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
50612         DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
50613         DUK_ASSERT_HEAPHDR_LINKS(heap, root);
50614         heap->heap_allocated = hdr;
50615 }
50616
50617 #if defined(DUK_USE_REFERENCE_COUNTING)
50618 DUK_INTERNAL void duk_heap_remove_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
50619         duk_heaphdr *prev;
50620         duk_heaphdr *next;
50621
50622         /* Strings are in string table. */
50623         DUK_ASSERT(hdr != NULL);
50624         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
50625
50626         /* Target 'hdr' must be in heap_allocated (not e.g. finalize_list).
50627          * If not, heap lists will become corrupted so assert early for it.
50628          */
50629 #if defined(DUK_USE_ASSERTIONS)
50630         {
50631                 duk_heaphdr *tmp;
50632                 for (tmp = heap->heap_allocated; tmp != NULL; tmp = DUK_HEAPHDR_GET_NEXT(heap, tmp)) {
50633                         if (tmp == hdr) {
50634                                 break;
50635                         }
50636                 }
50637                 DUK_ASSERT(tmp == hdr);
50638         }
50639 #endif
50640
50641         /* Read/write only once to minimize pointer compression calls. */
50642         prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
50643         next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
50644
50645         if (prev != NULL) {
50646                 DUK_ASSERT(heap->heap_allocated != hdr);
50647                 DUK_HEAPHDR_SET_NEXT(heap, prev, next);
50648         } else {
50649                 DUK_ASSERT(heap->heap_allocated == hdr);
50650                 heap->heap_allocated = next;
50651         }
50652         if (next != NULL) {
50653                 DUK_HEAPHDR_SET_PREV(heap, next, prev);
50654         } else {
50655                 ;
50656         }
50657 }
50658 #endif  /* DUK_USE_REFERENCE_COUNTING */
50659
50660 #if defined(DUK_USE_FINALIZER_SUPPORT)
50661 DUK_INTERNAL void duk_heap_insert_into_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
50662         duk_heaphdr *root;
50663
50664         root = heap->finalize_list;
50665 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
50666         DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
50667         if (root != NULL) {
50668                 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
50669                 DUK_HEAPHDR_SET_PREV(heap, root, hdr);
50670         }
50671 #endif
50672         DUK_HEAPHDR_SET_NEXT(heap, hdr, root);
50673         DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
50674         DUK_ASSERT_HEAPHDR_LINKS(heap, root);
50675         heap->finalize_list = hdr;
50676 }
50677 #endif  /* DUK_USE_FINALIZER_SUPPORT */
50678
50679 #if defined(DUK_USE_FINALIZER_SUPPORT)
50680 DUK_INTERNAL void duk_heap_remove_from_finalize_list(duk_heap *heap, duk_heaphdr *hdr) {
50681 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
50682         duk_heaphdr *next;
50683         duk_heaphdr *prev;
50684
50685         next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
50686         prev = DUK_HEAPHDR_GET_PREV(heap, hdr);
50687         if (next != NULL) {
50688                 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, next) == hdr);
50689                 DUK_HEAPHDR_SET_PREV(heap, next, prev);
50690         }
50691         if (prev == NULL) {
50692                 DUK_ASSERT(hdr == heap->finalize_list);
50693                 heap->finalize_list = next;
50694         } else {
50695                 DUK_ASSERT(hdr != heap->finalize_list);
50696                 DUK_HEAPHDR_SET_NEXT(heap, prev, next);
50697         }
50698 #else
50699         duk_heaphdr *next;
50700         duk_heaphdr *curr;
50701
50702         /* Random removal is expensive: we need to locate the previous element
50703          * because we don't have a 'prev' pointer.
50704          */
50705         curr = heap->finalize_list;
50706         if (curr == hdr) {
50707                 heap->finalize_list = DUK_HEAPHDR_GET_NEXT(heap, curr);
50708         } else {
50709                 DUK_ASSERT(hdr != heap->finalize_list);
50710                 for (;;) {
50711                         DUK_ASSERT(curr != NULL);  /* Caller responsibility. */
50712
50713                         next = DUK_HEAPHDR_GET_NEXT(heap, curr);
50714                         if (next == hdr) {
50715                                 next = DUK_HEAPHDR_GET_NEXT(heap, hdr);
50716                                 DUK_HEAPHDR_SET_NEXT(heap, curr, next);
50717                                 break;
50718                         }
50719                 }
50720         }
50721 #endif
50722 }
50723 #endif  /* DUK_USE_FINALIZER_SUPPORT */
50724
50725 #if defined(DUK_USE_ASSERTIONS)
50726 DUK_INTERNAL duk_bool_t duk_heap_in_heap_allocated(duk_heap *heap, duk_heaphdr *ptr) {
50727         duk_heaphdr *curr;
50728         DUK_ASSERT(heap != NULL);
50729
50730         for (curr = heap->heap_allocated; curr != NULL; curr = DUK_HEAPHDR_GET_NEXT(heap, curr)) {
50731                 if (curr == ptr) {
50732                         return 1;
50733                 }
50734         }
50735         return 0;
50736 }
50737 #endif  /* DUK_USE_ASSERTIONS */
50738
50739 #if defined(DUK_USE_INTERRUPT_COUNTER)
50740 DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
50741         duk_hthread *curr_thr;
50742
50743         DUK_ASSERT(heap != NULL);
50744
50745         if (new_thr != NULL) {
50746                 curr_thr = heap->curr_thread;
50747                 if (curr_thr == NULL) {
50748                         /* For initial entry use default value; zero forces an
50749                          * interrupt before executing the first insturction.
50750                          */
50751                         DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter"));
50752                         new_thr->interrupt_counter = 0;
50753                         new_thr->interrupt_init = 0;
50754                 } else {
50755                         /* Copy interrupt counter/init value state to new thread (if any).
50756                          * It's OK for new_thr to be the same as curr_thr.
50757                          */
50758 #if defined(DUK_USE_DEBUG)
50759                         if (new_thr != curr_thr) {
50760                                 DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter"));
50761                         }
50762 #endif
50763                         new_thr->interrupt_counter = curr_thr->interrupt_counter;
50764                         new_thr->interrupt_init = curr_thr->interrupt_init;
50765                 }
50766         } else {
50767                 DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes"));
50768         }
50769
50770         heap->curr_thread = new_thr;  /* may be NULL */
50771 }
50772 #endif  /* DUK_USE_INTERRUPT_COUNTER */
50773 #line 1 "duk_heap_refcount.c"
50774 /*
50775  *  Reference counting implementation.
50776  *
50777  *  INCREF/DECREF, finalization and freeing of objects whose refcount reaches
50778  *  zero (refzero).  These operations are very performance sensitive, so
50779  *  various small tricks are used in an attempt to maximize speed.
50780  */
50781
50782 /* #include duk_internal.h -> already included */
50783
50784 #if defined(DUK_USE_REFERENCE_COUNTING)
50785
50786 #if !defined(DUK_USE_DOUBLE_LINKED_HEAP)
50787 #error internal error, reference counting requires a double linked heap
50788 #endif
50789
50790 /*
50791  *  Heap object refcount finalization.
50792  *
50793  *  When an object is about to be freed, all other objects it refers to must
50794  *  be decref'd.  Refcount finalization does NOT free the object or its inner
50795  *  allocations (mark-and-sweep shares these helpers), it just manipulates
50796  *  the refcounts.
50797  *
50798  *  Note that any of the DECREFs may cause a refcount to drop to zero.  If so,
50799  *  the object won't be refzero processed inline, but will just be queued to
50800  *  refzero_list and processed by an earlier caller working on refzero_list,
50801  *  eliminating C recursion from even long refzero cascades.  If refzero
50802  *  finalization is triggered by mark-and-sweep, refzero conditions are ignored
50803  *  (objects are not even queued to refzero_list) because mark-and-sweep deals
50804  *  with them; refcounts are still updated so that they remain in sync with
50805  *  actual references.
50806  */
50807
50808 DUK_LOCAL void duk__decref_tvals_norz(duk_hthread *thr, duk_tval *tv, duk_idx_t count) {
50809         DUK_ASSERT(count == 0 || tv != NULL);
50810
50811         while (count-- > 0) {
50812                 DUK_TVAL_DECREF_NORZ(thr, tv);
50813                 tv++;
50814         }
50815 }
50816
50817 DUK_INTERNAL void duk_hobject_refcount_finalize_norz(duk_heap *heap, duk_hobject *h) {
50818         duk_hthread *thr;
50819         duk_uint_fast32_t i;
50820         duk_uint_fast32_t n;
50821         duk_propvalue *p_val;
50822         duk_tval *p_tv;
50823         duk_hstring **p_key;
50824         duk_uint8_t *p_flag;
50825         duk_hobject *h_proto;
50826
50827         DUK_ASSERT(heap != NULL);
50828         DUK_ASSERT(heap->heap_thread != NULL);
50829         DUK_ASSERT(h);
50830         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
50831
50832         thr = heap->heap_thread;
50833         DUK_ASSERT(thr != NULL);
50834
50835         p_key = DUK_HOBJECT_E_GET_KEY_BASE(heap, h);
50836         p_val = DUK_HOBJECT_E_GET_VALUE_BASE(heap, h);
50837         p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(heap, h);
50838         n = DUK_HOBJECT_GET_ENEXT(h);
50839         while (n-- > 0) {
50840                 duk_hstring *key;
50841
50842                 key = p_key[n];
50843                 if (DUK_UNLIKELY(key == NULL)) {
50844                         continue;
50845                 }
50846                 DUK_HSTRING_DECREF_NORZ(thr, key);
50847                 if (DUK_UNLIKELY(p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR)) {
50848                         duk_hobject *h_getset;
50849                         h_getset = p_val[n].a.get;
50850                         DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
50851                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
50852                         h_getset = p_val[n].a.set;
50853                         DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
50854                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
50855                 } else {
50856                         duk_tval *tv_val;
50857                         tv_val = &p_val[n].v;
50858                         DUK_TVAL_DECREF_NORZ(thr, tv_val);
50859                 }
50860         }
50861
50862         p_tv = DUK_HOBJECT_A_GET_BASE(heap, h);
50863         n = DUK_HOBJECT_GET_ASIZE(h);
50864         while (n-- > 0) {
50865                 duk_tval *tv_val;
50866                 tv_val = p_tv + n;
50867                 DUK_TVAL_DECREF_NORZ(thr, tv_val);
50868         }
50869
50870         /* Hash part is a 'weak reference' and doesn't contribute to refcounts. */
50871
50872         h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(heap, h);
50873         DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto));
50874         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto);
50875
50876         /* XXX: Object subclass tests are quite awkward at present, ideally
50877          * we should be able to switch-case here with a dense index (subtype
50878          * number or something).  For now, fast path plain objects and arrays
50879          * and bit test the rest individually.
50880          */
50881
50882         if (DUK_HOBJECT_HAS_FASTREFS(h)) {
50883                 /* Plain object or array, nothing more to do.  While a
50884                  * duk_harray has additional fields, none of them need
50885                  * DECREF updates.
50886                  */
50887                 DUK_ASSERT(DUK_HOBJECT_ALLOWS_FASTREFS(h));
50888                 return;
50889         }
50890         DUK_ASSERT(DUK_HOBJECT_PROHIBITS_FASTREFS(h));
50891
50892         /* Slow path: special object, start bit checks from most likely. */
50893
50894         /* XXX: reorg, more common first */
50895         if (DUK_HOBJECT_IS_COMPFUNC(h)) {
50896                 duk_hcompfunc *f = (duk_hcompfunc *) h;
50897                 duk_tval *tv, *tv_end;
50898                 duk_hobject **funcs, **funcs_end;
50899
50900                 DUK_ASSERT_HCOMPFUNC_VALID(f);
50901
50902                 if (DUK_LIKELY(DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL)) {
50903                         tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
50904                         tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
50905                         while (tv < tv_end) {
50906                                 DUK_TVAL_DECREF_NORZ(thr, tv);
50907                                 tv++;
50908                         }
50909
50910                         funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
50911                         funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
50912                         while (funcs < funcs_end) {
50913                                 duk_hobject *h_func;
50914                                 h_func = *funcs;
50915                                 DUK_ASSERT(h_func != NULL);
50916                                 DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_func));
50917                                 DUK_HCOMPFUNC_DECREF_NORZ(thr, (duk_hcompfunc *) h_func);
50918                                 funcs++;
50919                         }
50920                 } else {
50921                         /* May happen in some out-of-memory corner cases. */
50922                         DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref"));
50923                 }
50924
50925                 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f));
50926                 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f));
50927                 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(heap, f));
50928         } else if (DUK_HOBJECT_IS_DECENV(h)) {
50929                 duk_hdecenv *e = (duk_hdecenv *) h;
50930                 DUK_ASSERT_HDECENV_VALID(e);
50931                 DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, e->thread);
50932                 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, e->varmap);
50933         } else if (DUK_HOBJECT_IS_OBJENV(h)) {
50934                 duk_hobjenv *e = (duk_hobjenv *) h;
50935                 DUK_ASSERT_HOBJENV_VALID(e);
50936                 DUK_ASSERT(e->target != NULL);  /* Required for object environments. */
50937                 DUK_HOBJECT_DECREF_NORZ(thr, e->target);
50938 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
50939         } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
50940                 duk_hbufobj *b = (duk_hbufobj *) h;
50941                 DUK_ASSERT_HBUFOBJ_VALID(b);
50942                 DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf);
50943                 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop);
50944 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
50945         } else if (DUK_HOBJECT_IS_BOUNDFUNC(h)) {
50946                 duk_hboundfunc *f = (duk_hboundfunc *) (void *) h;
50947                 DUK_ASSERT_HBOUNDFUNC_VALID(f);
50948                 DUK_TVAL_DECREF_NORZ(thr, &f->target);
50949                 DUK_TVAL_DECREF_NORZ(thr, &f->this_binding);
50950                 duk__decref_tvals_norz(thr, f->args, f->nargs);
50951 #if defined(DUK_USE_ES6_PROXY)
50952         } else if (DUK_HOBJECT_IS_PROXY(h)) {
50953                 duk_hproxy *p = (duk_hproxy *) h;
50954                 DUK_ASSERT_HPROXY_VALID(p);
50955                 DUK_HOBJECT_DECREF_NORZ(thr, p->target);
50956                 DUK_HOBJECT_DECREF_NORZ(thr, p->handler);
50957 #endif  /* DUK_USE_ES6_PROXY */
50958         } else if (DUK_HOBJECT_IS_THREAD(h)) {
50959                 duk_hthread *t = (duk_hthread *) h;
50960                 duk_activation *act;
50961                 duk_tval *tv;
50962
50963                 DUK_ASSERT_HTHREAD_VALID(t);
50964
50965                 tv = t->valstack;
50966                 while (tv < t->valstack_top) {
50967                         DUK_TVAL_DECREF_NORZ(thr, tv);
50968                         tv++;
50969                 }
50970
50971                 for (act = t->callstack_curr; act != NULL; act = act->parent) {
50972                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) DUK_ACT_GET_FUNC(act));
50973                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->var_env);
50974                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->lex_env);
50975 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
50976                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->prev_caller);
50977 #endif
50978 #if 0  /* nothing now */
50979                         for (cat = act->cat; cat != NULL; cat = cat->parent) {
50980                         }
50981 #endif
50982                 }
50983
50984
50985                 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
50986                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) t->builtins[i]);
50987                 }
50988
50989                 DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, (duk_hthread *) t->resumer);
50990         } else {
50991                 /* We may come here if the object should have a FASTREFS flag
50992                  * but it's missing for some reason.  Assert for never getting
50993                  * here; however, other than performance, this is harmless.
50994                  */
50995                 DUK_D(DUK_DPRINT("missing FASTREFS flag for: %!iO", h));
50996                 DUK_ASSERT(0);
50997         }
50998 }
50999
51000 DUK_INTERNAL void duk_heaphdr_refcount_finalize_norz(duk_heap *heap, duk_heaphdr *hdr) {
51001         DUK_ASSERT(heap != NULL);
51002         DUK_ASSERT(heap->heap_thread != NULL);
51003         DUK_ASSERT(hdr != NULL);
51004
51005         if (DUK_HEAPHDR_IS_OBJECT(hdr)) {
51006                 duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) hdr);
51007         }
51008         /* DUK_HTYPE_BUFFER: nothing to finalize */
51009         /* DUK_HTYPE_STRING: nothing to finalize */
51010 }
51011
51012 /*
51013  *  Refzero processing for duk_hobject: queue a refzero'ed object to either
51014  *  finalize_list or refzero_list and process the relevent list(s) if
51015  *  necessary.
51016  *
51017  *  Refzero_list is single linked, with only 'prev' pointers set and valid.
51018  *  All 'next' pointers are intentionally left as garbage.  This doesn't
51019  *  matter because refzero_list is processed to completion before any other
51020  *  code (like mark-and-sweep) might walk the list.
51021  *
51022  *  In more detail:
51023  *
51024  *  - On first insert refzero_list is NULL and the new object becomes the
51025  *    first and only element on the list; duk__refcount_free_pending() is
51026  *    called and it starts processing the list from the initial element,
51027  *    i.e. the list tail.
51028  *
51029  *  - As each object is refcount finalized, new objects may be queued to
51030  *    refzero_list head.  Their 'next' pointers are left as garbage, but
51031  *    'prev' points are set correctly, with the element at refzero_list
51032  *    having a NULL 'prev' pointer.  The fact that refzero_list is non-NULL
51033  *    is used to reject (1) recursive duk__refcount_free_pending() and
51034  *    (2) finalize_list processing calls.
51035  *
51036  *  - When we're done with the current object, read its 'prev' pointer and
51037  *    free the object.  If 'prev' is NULL, we've reached head of list and are
51038  *    done: set refzero_list to NULL and process pending finalizers.  Otherwise
51039  *    continue processing the list.
51040  *
51041  *  A refzero cascade is free of side effects because it only involves
51042  *  queueing more objects and freeing memory; finalizer execution is blocked
51043  *  in the code path queueing objects to finalize_list.  As a result the
51044  *  initial refzero call (which triggers duk__refcount_free_pending()) must
51045  *  check finalize_list so that finalizers are executed snappily.
51046  *
51047  *  If finalize_list processing starts first, refzero may occur while we're
51048  *  processing finalizers.  That's fine: that particular refzero cascade is
51049  *  handled to completion without side effects.  Once the cascade is complete,
51050  *  we'll run pending finalizers but notice that we're already doing that and
51051  *  return.
51052  *
51053  *  This could be expanded to allow incremental freeing: just bail out
51054  *  early and resume at a future alloc/decref/refzero.  However, if that
51055  *  were done, the list structure would need to be kept consistent at all
51056  *  times, mark-and-sweep would need to handle refzero_list, etc.
51057  */
51058
51059 DUK_LOCAL void duk__refcount_free_pending(duk_heap *heap) {
51060         duk_heaphdr *curr;
51061 #if defined(DUK_USE_DEBUG)
51062         duk_int_t count = 0;
51063 #endif
51064
51065         DUK_ASSERT(heap != NULL);
51066
51067         curr = heap->refzero_list;
51068         DUK_ASSERT(curr != NULL);
51069         DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, curr) == NULL);  /* We're called on initial insert only. */
51070         /* curr->next is GARBAGE. */
51071
51072         do {
51073                 duk_heaphdr *prev;
51074
51075                 DUK_DDD(DUK_DDDPRINT("refzero processing %p: %!O", (void *) curr, (duk_heaphdr *) curr));
51076
51077 #if defined(DUK_USE_DEBUG)
51078                 count++;
51079 #endif
51080
51081                 DUK_ASSERT(curr != NULL);
51082                 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);  /* currently, always the case */
51083                 /* FINALIZED may be set; don't care about flags here. */
51084
51085                 /* Refcount finalize 'curr'.  Refzero_list must be non-NULL
51086                  * here to prevent recursive entry to duk__refcount_free_pending().
51087                  */
51088                 DUK_ASSERT(heap->refzero_list != NULL);
51089                 duk_hobject_refcount_finalize_norz(heap, (duk_hobject *) curr);
51090
51091                 prev = DUK_HEAPHDR_GET_PREV(heap, curr);
51092                 DUK_ASSERT((prev == NULL && heap->refzero_list == curr) || \
51093                            (prev != NULL && heap->refzero_list != curr));
51094                 /* prev->next is intentionally not updated and is garbage. */
51095
51096                 duk_free_hobject(heap, (duk_hobject *) curr);  /* Invalidates 'curr'. */
51097
51098                 curr = prev;
51099         } while (curr != NULL);
51100
51101         heap->refzero_list = NULL;
51102
51103         DUK_DD(DUK_DDPRINT("refzero processed %ld objects", (long) count));
51104 }
51105
51106 DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hobject(duk_heap *heap, duk_hobject *obj, duk_bool_t skip_free_pending) {
51107         duk_heaphdr *hdr;
51108         duk_heaphdr *root;
51109
51110         DUK_ASSERT(heap != NULL);
51111         DUK_ASSERT(heap->heap_thread != NULL);
51112         DUK_ASSERT(obj != NULL);
51113         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) obj) == DUK_HTYPE_OBJECT);
51114
51115         hdr = (duk_heaphdr *) obj;
51116
51117         /* Refzero'd objects must be in heap_allocated.  They can't be in
51118          * finalize_list because all objects on finalize_list have an
51119          * artificial +1 refcount bump.
51120          */
51121 #if defined(DUK_USE_ASSERTIONS)
51122         DUK_ASSERT(duk_heap_in_heap_allocated(heap, (duk_heaphdr *) obj));
51123 #endif
51124
51125         DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, hdr);
51126
51127 #if defined(DUK_USE_FINALIZER_SUPPORT)
51128         /* This finalizer check MUST BE side effect free.  It should also be
51129          * as fast as possible because it's applied to every object freed.
51130          */
51131         if (DUK_UNLIKELY(DUK_HOBJECT_HAS_FINALIZER_FAST(heap, (duk_hobject *) hdr) != 0U)) {
51132                 /* Special case: FINALIZED may be set if mark-and-sweep queued
51133                  * object for finalization, the finalizer was executed (and
51134                  * FINALIZED set), mark-and-sweep hasn't yet processed the
51135                  * object again, but its refcount drops to zero.  Free without
51136                  * running the finalizer again.
51137                  */
51138                 if (DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
51139                         DUK_D(DUK_DPRINT("refzero'd object has finalizer and FINALIZED is set -> free"));
51140                 } else {
51141                         /* Set FINALIZABLE flag so that all objects on finalize_list
51142                          * will have it set and are thus detectable based on the
51143                          * flag alone.
51144                          */
51145                         DUK_HEAPHDR_SET_FINALIZABLE(hdr);
51146                         DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
51147
51148 #if defined(DUK_USE_REFERENCE_COUNTING)
51149                         /* Bump refcount on finalize_list insert so that a
51150                          * refzero can never occur when an object is waiting
51151                          * for its finalizer call.  Refzero might otherwise
51152                          * now happen because we allow duk_push_heapptr() for
51153                          * objects pending finalization.
51154                          */
51155                         DUK_HEAPHDR_PREINC_REFCOUNT(hdr);
51156 #endif
51157                         DUK_HEAP_INSERT_INTO_FINALIZE_LIST(heap, hdr);
51158
51159                         /* Process finalizers unless skipping is explicitly
51160                          * requested (NORZ) or refzero_list is being processed
51161                          * (avoids side effects during a refzero cascade).
51162                          * If refzero_list is processed, the initial refzero
51163                          * call will run pending finalizers when refzero_list
51164                          * is done.
51165                          */
51166                         if (!skip_free_pending && heap->refzero_list == NULL) {
51167                                 duk_heap_process_finalize_list(heap);
51168                         }
51169                         return;
51170                 }
51171         }
51172 #endif  /* DUK_USE_FINALIZER_SUPPORT */
51173
51174         /* No need to finalize, free object via refzero_list. */
51175
51176         root = heap->refzero_list;
51177
51178         DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
51179         /* 'next' is left as GARBAGE. */
51180         heap->refzero_list = hdr;
51181
51182         if (root == NULL) {
51183                 /* Object is now queued.  Refzero_list was NULL so
51184                  * no-one is currently processing it; do it here.
51185                  * With refzero processing just doing a cascade of
51186                  * free calls, we can process it directly even when
51187                  * NORZ macros are used: there are no side effects.
51188                  */
51189                 duk__refcount_free_pending(heap);
51190                 DUK_ASSERT(heap->refzero_list == NULL);
51191
51192                 /* Process finalizers only after the entire cascade
51193                  * is finished.  In most cases there's nothing to
51194                  * finalize, so fast path check to avoid a call.
51195                  */
51196 #if defined(DUK_USE_FINALIZER_SUPPORT)
51197                 if (!skip_free_pending && DUK_UNLIKELY(heap->finalize_list != NULL)) {
51198                         duk_heap_process_finalize_list(heap);
51199                 }
51200 #endif
51201         } else {
51202                 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, root) == NULL);
51203                 DUK_HEAPHDR_SET_PREV(heap, root, hdr);
51204
51205                 /* Object is now queued.  Because refzero_list was
51206                  * non-NULL, it's already being processed by someone
51207                  * in the C call stack, so we're done.
51208                  */
51209         }
51210 }
51211
51212 #if defined(DUK_USE_FINALIZER_SUPPORT)
51213 DUK_INTERNAL DUK_ALWAYS_INLINE void duk_refzero_check_fast(duk_hthread *thr) {
51214         DUK_ASSERT(thr != NULL);
51215         DUK_ASSERT(thr->heap != NULL);
51216         DUK_ASSERT(thr->heap->refzero_list == NULL);  /* Processed to completion inline. */
51217
51218         if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) {
51219                 duk_heap_process_finalize_list(thr->heap);
51220         }
51221 }
51222
51223 DUK_INTERNAL void duk_refzero_check_slow(duk_hthread *thr) {
51224         DUK_ASSERT(thr != NULL);
51225         DUK_ASSERT(thr->heap != NULL);
51226         DUK_ASSERT(thr->heap->refzero_list == NULL);  /* Processed to completion inline. */
51227
51228         if (DUK_UNLIKELY(thr->heap->finalize_list != NULL)) {
51229                 duk_heap_process_finalize_list(thr->heap);
51230         }
51231 }
51232 #endif  /* DUK_USE_FINALIZER_SUPPORT */
51233
51234 /*
51235  *  Refzero processing for duk_hstring.
51236  */
51237
51238 DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hstring(duk_heap *heap, duk_hstring *str) {
51239         DUK_ASSERT(heap != NULL);
51240         DUK_ASSERT(heap->heap_thread != NULL);
51241         DUK_ASSERT(str != NULL);
51242         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) str) == DUK_HTYPE_STRING);
51243
51244         duk_heap_strcache_string_remove(heap, str);
51245         duk_heap_strtable_unlink(heap, str);
51246         duk_free_hstring(heap, str);
51247 }
51248
51249 /*
51250  *  Refzero processing for duk_hbuffer.
51251  */
51252
51253 DUK_LOCAL DUK_INLINE void duk__refcount_refzero_hbuffer(duk_heap *heap, duk_hbuffer *buf) {
51254         DUK_ASSERT(heap != NULL);
51255         DUK_ASSERT(heap->heap_thread != NULL);
51256         DUK_ASSERT(buf != NULL);
51257         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) buf) == DUK_HTYPE_BUFFER);
51258
51259         DUK_HEAP_REMOVE_FROM_HEAP_ALLOCATED(heap, (duk_heaphdr *) buf);
51260         duk_free_hbuffer(heap, buf);
51261 }
51262
51263 /*
51264  *  Incref and decref functions.
51265  *
51266  *  Decref may trigger immediate refzero handling, which may free and finalize
51267  *  an arbitrary number of objects (a "DECREF cascade").
51268  *
51269  *  Refzero handling is skipped entirely if (1) mark-and-sweep is running or
51270  *  (2) execution is paused in the debugger.  The objects are left in the heap,
51271  *  and will be freed by mark-and-sweep or eventual heap destruction.
51272  *
51273  *  This is necessary during mark-and-sweep because refcounts are also updated
51274  *  during the sweep phase (otherwise objects referenced by a swept object
51275  *  would have incorrect refcounts) which then calls here.  This could be
51276  *  avoided by using separate decref macros in mark-and-sweep; however,
51277  *  mark-and-sweep also calls finalizers which would use the ordinary decref
51278  *  macros anyway.
51279  *
51280  *  We can't process refzeros (= free objects) when the debugger is running
51281  *  as the debugger might make an object unreachable but still continue
51282  *  inspecting it (or even cause it to be pushed back).  So we must rely on
51283  *  mark-and-sweep to collect them.
51284  *
51285  *  The DUK__RZ_SUPPRESS_CHECK() condition is also used in heap destruction
51286  *  when running finalizers for remaining objects: the flag prevents objects
51287  *  from being moved around in heap linked lists while that's being done.
51288  *
51289  *  The suppress condition is important to performance.
51290  */
51291
51292 #define DUK__RZ_SUPPRESS_ASSERT1() do { \
51293                 DUK_ASSERT(thr != NULL); \
51294                 DUK_ASSERT(thr->heap != NULL); \
51295                 /* When mark-and-sweep runs, heap_thread must exist. */ \
51296                 DUK_ASSERT(thr->heap->ms_running == 0 || thr->heap->heap_thread != NULL); \
51297                 /* When mark-and-sweep runs, the 'thr' argument always matches heap_thread. \
51298                  * This could be used to e.g. suppress check against 'thr' directly (and \
51299                  * knowing it would be heap_thread); not really used now. \
51300                  */ \
51301                 DUK_ASSERT(thr->heap->ms_running == 0 || thr == thr->heap->heap_thread); \
51302                 /* We may be called when the heap is initializing and we process \
51303                  * refzeros normally, but mark-and-sweep and finalizers are prevented \
51304                  * if that's the case. \
51305                  */ \
51306                 DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->ms_prevent_count > 0); \
51307                 DUK_ASSERT(thr->heap->heap_initializing == 0 || thr->heap->pf_prevent_count > 0); \
51308         } while (0)
51309
51310 #if defined(DUK_USE_DEBUGGER_SUPPORT)
51311 #define DUK__RZ_SUPPRESS_ASSERT2() do { \
51312                 /* When debugger is paused, ms_running is set. */ \
51313                 DUK_ASSERT(!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->ms_running != 0); \
51314         } while (0)
51315 #define DUK__RZ_SUPPRESS_COND()  (heap->ms_running != 0)
51316 #else
51317 #define DUK__RZ_SUPPRESS_ASSERT2() do { } while (0)
51318 #define DUK__RZ_SUPPRESS_COND()  (heap->ms_running != 0)
51319 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
51320
51321 #define DUK__RZ_SUPPRESS_CHECK() do { \
51322                 DUK__RZ_SUPPRESS_ASSERT1(); \
51323                 DUK__RZ_SUPPRESS_ASSERT2(); \
51324                 if (DUK_UNLIKELY(DUK__RZ_SUPPRESS_COND())) { \
51325                         DUK_DDD(DUK_DDDPRINT("refzero handling suppressed (not even queued) when mark-and-sweep running, object: %p", (void *) h)); \
51326                         return; \
51327                 } \
51328         } while (0)
51329
51330 #define DUK__RZ_STRING() do { \
51331                 duk__refcount_refzero_hstring(heap, (duk_hstring *) h); \
51332         } while (0)
51333 #define DUK__RZ_BUFFER() do { \
51334                 duk__refcount_refzero_hbuffer(heap, (duk_hbuffer *) h); \
51335         } while (0)
51336 #define DUK__RZ_OBJECT() do { \
51337                 duk__refcount_refzero_hobject(heap, (duk_hobject *) h, skip_free_pending); \
51338         } while (0)
51339
51340 /* XXX: test the effect of inlining here vs. NOINLINE in refzero helpers */
51341 #if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
51342 #define DUK__RZ_INLINE DUK_ALWAYS_INLINE
51343 #else
51344 #define DUK__RZ_INLINE /*nop*/
51345 #endif
51346
51347 DUK_LOCAL DUK__RZ_INLINE void duk__hstring_refzero_helper(duk_hthread *thr, duk_hstring *h) {
51348         duk_heap *heap;
51349
51350         DUK_ASSERT(thr != NULL);
51351         DUK_ASSERT(h != NULL);
51352         heap = thr->heap;
51353
51354         DUK__RZ_SUPPRESS_CHECK();
51355         DUK__RZ_STRING();
51356 }
51357
51358 DUK_LOCAL DUK__RZ_INLINE void duk__hbuffer_refzero_helper(duk_hthread *thr, duk_hbuffer *h) {
51359         duk_heap *heap;
51360
51361         DUK_ASSERT(thr != NULL);
51362         DUK_ASSERT(h != NULL);
51363         heap = thr->heap;
51364
51365         DUK__RZ_SUPPRESS_CHECK();
51366         DUK__RZ_BUFFER();
51367 }
51368
51369 DUK_LOCAL DUK__RZ_INLINE void duk__hobject_refzero_helper(duk_hthread *thr, duk_hobject *h, duk_bool_t skip_free_pending) {
51370         duk_heap *heap;
51371
51372         DUK_ASSERT(thr != NULL);
51373         DUK_ASSERT(h != NULL);
51374         heap = thr->heap;
51375
51376         DUK__RZ_SUPPRESS_CHECK();
51377         DUK__RZ_OBJECT();
51378 }
51379
51380 DUK_LOCAL DUK__RZ_INLINE void duk__heaphdr_refzero_helper(duk_hthread *thr, duk_heaphdr *h, duk_bool_t skip_free_pending) {
51381         duk_heap *heap;
51382         duk_small_uint_t htype;
51383
51384         DUK_ASSERT(thr != NULL);
51385         DUK_ASSERT(h != NULL);
51386         heap = thr->heap;
51387
51388         htype = (duk_small_uint_t) DUK_HEAPHDR_GET_TYPE(h);
51389         DUK__RZ_SUPPRESS_CHECK();
51390
51391         switch (htype) {
51392         case DUK_HTYPE_STRING:
51393                 /* Strings have no internal references but do have "weak"
51394                  * references in the string cache.  Also note that strings
51395                  * are not on the heap_allocated list like other heap
51396                  * elements.
51397                  */
51398
51399                 DUK__RZ_STRING();
51400                 break;
51401
51402         case DUK_HTYPE_OBJECT:
51403                 /* Objects have internal references.  Must finalize through
51404                  * the "refzero" work list.
51405                  */
51406
51407                 DUK__RZ_OBJECT();
51408                 break;
51409
51410         default:
51411                 /* Buffers have no internal references.  However, a dynamic
51412                  * buffer has a separate allocation for the buffer.  This is
51413                  * freed by duk_heap_free_heaphdr_raw().
51414                  */
51415
51416                 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h) == DUK_HTYPE_BUFFER);
51417                 DUK__RZ_BUFFER();
51418                 break;
51419         }
51420 }
51421
51422 DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
51423         duk__heaphdr_refzero_helper(thr, h, 0 /*skip_free_pending*/);
51424 }
51425
51426 DUK_INTERNAL DUK_NOINLINE void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) {
51427         duk__heaphdr_refzero_helper(thr, h, 1 /*skip_free_pending*/);
51428 }
51429
51430 DUK_INTERNAL DUK_NOINLINE void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) {
51431         duk__hstring_refzero_helper(thr, h);
51432 }
51433
51434 DUK_INTERNAL DUK_NOINLINE void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) {
51435         duk__hbuffer_refzero_helper(thr, h);
51436 }
51437
51438 DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h) {
51439         duk__hobject_refzero_helper(thr, h, 0 /*skip_free_pending*/);
51440 }
51441
51442 DUK_INTERNAL DUK_NOINLINE void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) {
51443         duk__hobject_refzero_helper(thr, h, 1 /*skip_free_pending*/);
51444 }
51445
51446 #if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
51447 DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
51448         DUK_ASSERT(tv != NULL);
51449
51450         if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
51451                 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
51452                 DUK_ASSERT(h != NULL);
51453                 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
51454                 DUK_ASSERT_DISABLE(h->h_refcount >= 0);
51455                 DUK_HEAPHDR_PREINC_REFCOUNT(h);
51456                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) != 0);  /* No wrapping. */
51457         }
51458 }
51459
51460 DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
51461         DUK_ASSERT(thr != NULL);
51462         DUK_ASSERT(tv != NULL);
51463
51464         if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
51465                 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
51466                 DUK_ASSERT(h != NULL);
51467                 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
51468                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
51469 #if 0
51470                 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
51471                         return;
51472                 }
51473                 duk_heaphdr_refzero(thr, h);
51474 #else
51475                 duk_heaphdr_decref(thr, h);
51476 #endif
51477         }
51478 }
51479
51480 DUK_INTERNAL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv) {
51481         DUK_ASSERT(thr != NULL);
51482         DUK_ASSERT(tv != NULL);
51483
51484         if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
51485                 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
51486                 DUK_ASSERT(h != NULL);
51487                 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
51488                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
51489 #if 0
51490                 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
51491                         return;
51492                 }
51493                 duk_heaphdr_refzero_norz(thr, h);
51494 #else
51495                 duk_heaphdr_decref_norz(thr, h);
51496 #endif
51497         }
51498 }
51499 #endif  /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
51500
51501 #define DUK__DECREF_ASSERTS() do { \
51502                 DUK_ASSERT(thr != NULL); \
51503                 DUK_ASSERT(thr->heap != NULL); \
51504                 DUK_ASSERT(h != NULL); \
51505                 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((duk_heaphdr *) h)); \
51506                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) >= 1); \
51507         } while (0)
51508 #if defined(DUK_USE_ROM_OBJECTS)
51509 #define DUK__INCREF_SHARED() do { \
51510                 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
51511                         return; \
51512                 } \
51513                 DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \
51514                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0);  /* No wrapping. */ \
51515         } while (0)
51516 #define DUK__DECREF_SHARED() do { \
51517                 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
51518                         return; \
51519                 } \
51520                 if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
51521                         return; \
51522                 } \
51523         } while (0)
51524 #else
51525 #define DUK__INCREF_SHARED() do { \
51526                 DUK_HEAPHDR_PREINC_REFCOUNT((duk_heaphdr *) h); \
51527                 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) != 0);  /* No wrapping. */ \
51528         } while (0)
51529 #define DUK__DECREF_SHARED() do { \
51530                 if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
51531                         return; \
51532                 } \
51533         } while (0)
51534 #endif
51535
51536 #if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
51537 /* This will in practice be inlined because it's just an INC instructions
51538  * and a bit test + INC when ROM objects are enabled.
51539  */
51540 DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) {
51541         DUK_ASSERT(h != NULL);
51542         DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
51543         DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
51544
51545         DUK__INCREF_SHARED();
51546 }
51547
51548 DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
51549         DUK__DECREF_ASSERTS();
51550         DUK__DECREF_SHARED();
51551         duk_heaphdr_refzero(thr, h);
51552
51553         /* Forced mark-and-sweep when GC torture enabled; this could happen
51554          * on any DECREF (but not DECREF_NORZ).
51555          */
51556         DUK_GC_TORTURE(thr->heap);
51557 }
51558 DUK_INTERNAL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h) {
51559         DUK__DECREF_ASSERTS();
51560         DUK__DECREF_SHARED();
51561         duk_heaphdr_refzero_norz(thr, h);
51562 }
51563 #endif  /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
51564
51565 #if 0  /* Not needed. */
51566 DUK_INTERNAL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h) {
51567         DUK__DECREF_ASSERTS();
51568         DUK__DECREF_SHARED();
51569         duk_hstring_refzero(thr, h);
51570 }
51571 DUK_INTERNAL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h) {
51572         DUK__DECREF_ASSERTS();
51573         DUK__DECREF_SHARED();
51574         duk_hstring_refzero_norz(thr, h);
51575 }
51576 DUK_INTERNAL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h) {
51577         DUK__DECREF_ASSERTS();
51578         DUK__DECREF_SHARED();
51579         duk_hbuffer_refzero(thr, h);
51580 }
51581 DUK_INTERNAL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h) {
51582         DUK__DECREF_ASSERTS();
51583         DUK__DECREF_SHARED();
51584         duk_hbuffer_refzero_norz(thr, h);
51585 }
51586 DUK_INTERNAL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h) {
51587         DUK__DECREF_ASSERTS();
51588         DUK__DECREF_SHARED();
51589         duk_hobject_refzero(thr, h);
51590 }
51591 DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) {
51592         DUK__DECREF_ASSERTS();
51593         DUK__DECREF_SHARED();
51594         duk_hobject_refzero_norz(thr, h);
51595 }
51596 #endif
51597
51598 #else  /* DUK_USE_REFERENCE_COUNTING */
51599
51600 /* no refcounting */
51601
51602 #endif  /* DUK_USE_REFERENCE_COUNTING */
51603
51604 /* automatic undefs */
51605 #undef DUK__DECREF_ASSERTS
51606 #undef DUK__DECREF_SHARED
51607 #undef DUK__INCREF_SHARED
51608 #undef DUK__RZ_BUFFER
51609 #undef DUK__RZ_INLINE
51610 #undef DUK__RZ_OBJECT
51611 #undef DUK__RZ_STRING
51612 #undef DUK__RZ_SUPPRESS_ASSERT1
51613 #undef DUK__RZ_SUPPRESS_ASSERT2
51614 #undef DUK__RZ_SUPPRESS_CHECK
51615 #undef DUK__RZ_SUPPRESS_COND
51616 #line 1 "duk_heap_stringcache.c"
51617 /*
51618  *  String cache.
51619  *
51620  *  Provides a cache to optimize indexed string lookups.  The cache keeps
51621  *  track of (byte offset, char offset) states for a fixed number of strings.
51622  *  Otherwise we'd need to scan from either end of the string, as we store
51623  *  strings in (extended) UTF-8.
51624  */
51625
51626 /* #include duk_internal.h -> already included */
51627
51628 /*
51629  *  Delete references to given hstring from the heap string cache.
51630  *
51631  *  String cache references are 'weak': they are not counted towards
51632  *  reference counts, nor serve as roots for mark-and-sweep.  When an
51633  *  object is about to be freed, such references need to be removed.
51634  */
51635
51636 DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
51637         duk_uint_t i;
51638         for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
51639                 duk_strcache_entry *c = heap->strcache + i;
51640                 if (c->h == h) {
51641                         DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
51642                                            (void *) h, (void *) heap));
51643                         c->h = NULL;
51644
51645                         /* XXX: the string shouldn't appear twice, but we now loop to the
51646                          * end anyway; if fixed, add a looping assertion to ensure there
51647                          * is no duplicate.
51648                          */
51649                 }
51650         }
51651 }
51652
51653 /*
51654  *  String scanning helpers
51655  *
51656  *  All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are
51657  *  considered to contribute a character.  This must match how string
51658  *  character length is computed.
51659  */
51660
51661 DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
51662         while (n > 0) {
51663                 for (;;) {
51664                         p++;
51665                         if (p >= q) {
51666                                 return NULL;
51667                         }
51668                         if ((*p & 0xc0) != 0x80) {
51669                                 break;
51670                         }
51671                 }
51672                 n--;
51673         }
51674         return p;
51675 }
51676
51677 DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
51678         while (n > 0) {
51679                 for (;;) {
51680                         p--;
51681                         if (p < q) {
51682                                 return NULL;
51683                         }
51684                         if ((*p & 0xc0) != 0x80) {
51685                                 break;
51686                         }
51687                 }
51688                 n--;
51689         }
51690         return p;
51691 }
51692
51693 /*
51694  *  Convert char offset to byte offset
51695  *
51696  *  Avoid using the string cache if possible: for ASCII strings byte and
51697  *  char offsets are equal and for short strings direct scanning may be
51698  *  better than using the string cache (which may evict a more important
51699  *  entry).
51700  *
51701  *  Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t).
51702  *  Better typing might be to use duk_size_t.
51703  *
51704  *  Caller should ensure 'char_offset' is within the string bounds [0,charlen]
51705  *  (endpoint is inclusive).  If this is not the case, no memory unsafe
51706  *  behavior will happen but an error will be thrown.
51707  */
51708
51709 DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
51710         duk_heap *heap;
51711         duk_strcache_entry *sce;
51712         duk_uint_fast32_t byte_offset;
51713         duk_uint_t i;
51714         duk_bool_t use_cache;
51715         duk_uint_fast32_t dist_start, dist_end, dist_sce;
51716         duk_uint_fast32_t char_length;
51717         const duk_uint8_t *p_start;
51718         const duk_uint8_t *p_end;
51719         const duk_uint8_t *p_found;
51720
51721         /*
51722          *  For ASCII strings, the answer is simple.
51723          */
51724
51725         if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) {
51726                 return char_offset;
51727         }
51728
51729         char_length = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h);
51730         DUK_ASSERT(char_offset <= char_length);
51731
51732         if (DUK_LIKELY(DUK_HSTRING_IS_ASCII(h))) {
51733                 /* Must recheck because the 'is ascii' flag may be set
51734                  * lazily.  Alternatively, we could just compare charlen
51735                  * to bytelen.
51736                  */
51737                 return char_offset;
51738         }
51739
51740         /*
51741          *  For non-ASCII strings, we need to scan forwards or backwards
51742          *  from some starting point.  The starting point may be the start
51743          *  or end of the string, or some cached midpoint in the string
51744          *  cache.
51745          *
51746          *  For "short" strings we simply scan without checking or updating
51747          *  the cache.  For longer strings we check and update the cache as
51748          *  necessary, inserting a new cache entry if none exists.
51749          */
51750
51751         DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
51752                              (void *) h, (long) char_offset,
51753                              (long) DUK_HSTRING_GET_CHARLEN(h),
51754                              (long) DUK_HSTRING_GET_BYTELEN(h)));
51755
51756         heap = thr->heap;
51757         sce = NULL;
51758         use_cache = (char_length > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
51759
51760         if (use_cache) {
51761 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
51762                 DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
51763                 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
51764                         duk_strcache_entry *c = heap->strcache + i;
51765                         DUK_DDD(DUK_DDDPRINT("  [%ld] -> h=%p, cidx=%ld, bidx=%ld",
51766                                              (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
51767                 }
51768 #endif
51769
51770                 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
51771                         duk_strcache_entry *c = heap->strcache + i;
51772
51773                         if (c->h == h) {
51774                                 sce = c;
51775                                 break;
51776                         }
51777                 }
51778         }
51779
51780         /*
51781          *  Scan from shortest distance:
51782          *    - start of string
51783          *    - end of string
51784          *    - cache entry (if exists)
51785          */
51786
51787         DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
51788         dist_start = char_offset;
51789         dist_end = char_length - char_offset;
51790         dist_sce = 0; DUK_UNREF(dist_sce);  /* initialize for debug prints, needed if sce==NULL */
51791
51792         p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
51793         p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
51794         p_found = NULL;
51795
51796         if (sce) {
51797                 if (char_offset >= sce->cidx) {
51798                         dist_sce = char_offset - sce->cidx;
51799                         if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
51800                                 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
51801                                                      "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
51802                                                      "scan forwards from sce",
51803                                                      (long) use_cache, (void *) (sce ? sce->h : NULL),
51804                                                      (sce ? (long) sce->cidx : (long) -1),
51805                                                      (sce ? (long) sce->bidx : (long) -1),
51806                                                      (long) dist_start, (long) dist_end, (long) dist_sce));
51807
51808                                 p_found = duk__scan_forwards(p_start + sce->bidx,
51809                                                              p_end,
51810                                                              dist_sce);
51811                                 goto scan_done;
51812                         }
51813                 } else {
51814                         dist_sce = sce->cidx - char_offset;
51815                         if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
51816                                 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
51817                                                      "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
51818                                                      "scan backwards from sce",
51819                                                      (long) use_cache, (void *) (sce ? sce->h : NULL),
51820                                                      (sce ? (long) sce->cidx : (long) -1),
51821                                                      (sce ? (long) sce->bidx : (long) -1),
51822                                                      (long) dist_start, (long) dist_end, (long) dist_sce));
51823
51824                                 p_found = duk__scan_backwards(p_start + sce->bidx,
51825                                                               p_start,
51826                                                               dist_sce);
51827                                 goto scan_done;
51828                         }
51829                 }
51830         }
51831
51832         /* no sce, or sce scan not best */
51833
51834         if (dist_start <= dist_end) {
51835                 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
51836                                      "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
51837                                      "scan forwards from string start",
51838                                      (long) use_cache, (void *) (sce ? sce->h : NULL),
51839                                      (sce ? (long) sce->cidx : (long) -1),
51840                                      (sce ? (long) sce->bidx : (long) -1),
51841                                      (long) dist_start, (long) dist_end, (long) dist_sce));
51842
51843                 p_found = duk__scan_forwards(p_start,
51844                                              p_end,
51845                                              dist_start);
51846         } else {
51847                 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
51848                                      "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
51849                                      "scan backwards from string end",
51850                                      (long) use_cache, (void *) (sce ? sce->h : NULL),
51851                                      (sce ? (long) sce->cidx : (long) -1),
51852                                      (sce ? (long) sce->bidx : (long) -1),
51853                                      (long) dist_start, (long) dist_end, (long) dist_sce));
51854
51855                 p_found = duk__scan_backwards(p_end,
51856                                               p_start,
51857                                               dist_end);
51858         }
51859
51860  scan_done:
51861
51862         if (DUK_UNLIKELY(p_found == NULL)) {
51863                 /* Scan error: this shouldn't normally happen; it could happen if
51864                  * string is not valid UTF-8 data, and clen/blen are not consistent
51865                  * with the scanning algorithm.
51866                  */
51867                 goto scan_error;
51868         }
51869
51870         DUK_ASSERT(p_found >= p_start);
51871         DUK_ASSERT(p_found <= p_end);  /* may be equal */
51872         byte_offset = (duk_uint32_t) (p_found - p_start);
51873
51874         DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
51875                              (void *) h, (long) char_offset, (long) byte_offset));
51876
51877         /*
51878          *  Update cache entry (allocating if necessary), and move the
51879          *  cache entry to the first place (in an "LRU" policy).
51880          */
51881
51882         if (use_cache) {
51883                 /* update entry, allocating if necessary */
51884                 if (!sce) {
51885                         sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1;  /* take last entry */
51886                         sce->h = h;
51887                 }
51888                 DUK_ASSERT(sce != NULL);
51889                 sce->bidx = (duk_uint32_t) (p_found - p_start);
51890                 sce->cidx = (duk_uint32_t) char_offset;
51891
51892                 /* LRU: move our entry to first */
51893                 if (sce > &heap->strcache[0]) {
51894                         /*
51895                          *   A                  C
51896                          *   B                  A
51897                          *   C <- sce    ==>    B
51898                          *   D                  D
51899                          */
51900                         duk_strcache_entry tmp;
51901
51902                         tmp = *sce;
51903                         duk_memmove((void *) (&heap->strcache[1]),
51904                                     (const void *) (&heap->strcache[0]),
51905                                     (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
51906                         heap->strcache[0] = tmp;
51907
51908                         /* 'sce' points to the wrong entry here, but is no longer used */
51909                 }
51910 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
51911                 DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
51912                 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
51913                         duk_strcache_entry *c = heap->strcache + i;
51914                         DUK_DDD(DUK_DDDPRINT("  [%ld] -> h=%p, cidx=%ld, bidx=%ld",
51915                                              (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
51916                 }
51917 #endif
51918         }
51919
51920         return byte_offset;
51921
51922  scan_error:
51923         DUK_ERROR_INTERNAL(thr);
51924         DUK_WO_NORETURN(return 0;);
51925 }
51926 #line 1 "duk_heap_stringtable.c"
51927 /*
51928  *  Heap string table handling, string interning.
51929  */
51930
51931 /* #include duk_internal.h -> already included */
51932
51933 /* Resize checks not needed if minsize == maxsize, typical for low memory
51934  * targets.
51935  */
51936 #define DUK__STRTAB_RESIZE_CHECK
51937 #if (DUK_USE_STRTAB_MINSIZE == DUK_USE_STRTAB_MAXSIZE)
51938 #undef DUK__STRTAB_RESIZE_CHECK
51939 #endif
51940
51941 #if defined(DUK_USE_STRTAB_PTRCOMP)
51942 #define DUK__HEAPPTR_ENC16(heap,ptr)    DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (ptr))
51943 #define DUK__HEAPPTR_DEC16(heap,val)    DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (val))
51944 #define DUK__GET_STRTABLE(heap)         ((heap)->strtable16)
51945 #else
51946 #define DUK__HEAPPTR_ENC16(heap,ptr)    (ptr)
51947 #define DUK__HEAPPTR_DEC16(heap,val)    (val)
51948 #define DUK__GET_STRTABLE(heap)         ((heap)->strtable)
51949 #endif
51950
51951 #define DUK__STRTAB_U32_MAX_STRLEN      10               /* 4'294'967'295 */
51952
51953 /*
51954  *  Debug dump stringtable.
51955  */
51956
51957 #if defined(DUK_USE_DEBUG)
51958 DUK_INTERNAL void duk_heap_strtable_dump(duk_heap *heap) {
51959 #if defined(DUK_USE_STRTAB_PTRCOMP)
51960         duk_uint16_t *strtable;
51961 #else
51962         duk_hstring **strtable;
51963 #endif
51964         duk_uint32_t i;
51965         duk_hstring *h;
51966         duk_size_t count_total = 0;
51967         duk_size_t count_chain;
51968         duk_size_t count_chain_min = DUK_SIZE_MAX;
51969         duk_size_t count_chain_max = 0;
51970         duk_size_t count_len[8];  /* chain lengths from 0 to 7 */
51971
51972         if (heap == NULL) {
51973                 DUK_D(DUK_DPRINT("string table, heap=NULL"));
51974                 return;
51975         }
51976
51977         strtable = DUK__GET_STRTABLE(heap);
51978         if (strtable == NULL) {
51979                 DUK_D(DUK_DPRINT("string table, strtab=NULL"));
51980                 return;
51981         }
51982
51983         duk_memzero((void *) count_len, sizeof(count_len));
51984         for (i = 0; i < heap->st_size; i++) {
51985                 h = DUK__HEAPPTR_DEC16(heap, strtable[i]);
51986                 count_chain = 0;
51987                 while (h != NULL) {
51988                         count_chain++;
51989                         h = h->hdr.h_next;
51990                 }
51991                 if (count_chain < sizeof(count_len) / sizeof(duk_size_t)) {
51992                         count_len[count_chain]++;
51993                 }
51994                 count_chain_max = (count_chain > count_chain_max ? count_chain : count_chain_max);
51995                 count_chain_min = (count_chain < count_chain_min ? count_chain : count_chain_min);
51996                 count_total += count_chain;
51997         }
51998
51999         DUK_D(DUK_DPRINT("string table, strtab=%p, count=%lu, chain min=%lu max=%lu avg=%lf: "
52000                          "counts: %lu %lu %lu %lu %lu %lu %lu %lu ...",
52001                          (void *) heap->strtable, (unsigned long) count_total,
52002                          (unsigned long) count_chain_min, (unsigned long) count_chain_max,
52003                          (double) count_total / (double) heap->st_size,
52004                          (unsigned long) count_len[0], (unsigned long) count_len[1],
52005                          (unsigned long) count_len[2], (unsigned long) count_len[3],
52006                          (unsigned long) count_len[4], (unsigned long) count_len[5],
52007                          (unsigned long) count_len[6], (unsigned long) count_len[7]));
52008 }
52009 #endif  /* DUK_USE_DEBUG */
52010
52011 /*
52012  *  Assertion helper to ensure strtable is populated correctly.
52013  */
52014
52015 #if defined(DUK_USE_ASSERTIONS)
52016 DUK_LOCAL void duk__strtable_assert_checks(duk_heap *heap) {
52017 #if defined(DUK_USE_STRTAB_PTRCOMP)
52018         duk_uint16_t *strtable;
52019 #else
52020         duk_hstring **strtable;
52021 #endif
52022         duk_uint32_t i;
52023         duk_hstring *h;
52024         duk_size_t count = 0;
52025
52026         DUK_ASSERT(heap != NULL);
52027
52028         strtable = DUK__GET_STRTABLE(heap);
52029         if (strtable != NULL) {
52030                 DUK_ASSERT(heap->st_size != 0);
52031                 DUK_ASSERT(heap->st_mask == heap->st_size - 1);
52032
52033                 for (i = 0; i < heap->st_size; i++) {
52034                         h = DUK__HEAPPTR_DEC16(heap, strtable[i]);
52035                         while (h != NULL) {
52036                                 DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i);
52037                                 count++;
52038                                 h = h->hdr.h_next;
52039                         }
52040                 }
52041         } else {
52042                 DUK_ASSERT(heap->st_size == 0);
52043                 DUK_ASSERT(heap->st_mask == 0);
52044         }
52045
52046 #if defined(DUK__STRTAB_RESIZE_CHECK)
52047         DUK_ASSERT(count == (duk_size_t) heap->st_count);
52048 #endif
52049 }
52050 #endif  /* DUK_USE_ASSERTIONS */
52051
52052 /*
52053  *  Allocate and initialize a duk_hstring.
52054  *
52055  *  Returns a NULL if allocation or initialization fails for some reason.
52056  *
52057  *  The string won't be inserted into the string table and isn't tracked in
52058  *  any way (link pointers will be NULL).  The caller must place the string
52059  *  into the string table without any risk of a longjmp, otherwise the string
52060  *  is leaked.
52061  */
52062
52063 DUK_LOCAL duk_hstring *duk__strtable_alloc_hstring(duk_heap *heap,
52064                                                    const duk_uint8_t *str,
52065                                                    duk_uint32_t blen,
52066                                                    duk_uint32_t strhash,
52067                                                    const duk_uint8_t *extdata) {
52068         duk_hstring *res;
52069         const duk_uint8_t *data;
52070 #if !defined(DUK_USE_HSTRING_ARRIDX)
52071         duk_uarridx_t dummy;
52072 #endif
52073
52074         DUK_ASSERT(heap != NULL);
52075         DUK_UNREF(extdata);
52076
52077 #if defined(DUK_USE_STRLEN16)
52078         /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */
52079         if (blen > 0xffffUL) {
52080                 DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern"));
52081                 goto alloc_error;
52082         }
52083 #endif
52084
52085         /* XXX: Memzeroing the allocated structure is not really necessary
52086          * because we could just initialize all fields explicitly (almost
52087          * all fields are initialized explicitly anyway).
52088          */
52089 #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
52090         if (extdata) {
52091                 res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring_external));
52092                 if (DUK_UNLIKELY(res == NULL)) {
52093                         goto alloc_error;
52094                 }
52095                 duk_memzero(res, sizeof(duk_hstring_external));
52096 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
52097                 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
52098 #endif
52099                 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA);
52100
52101                 DUK_ASSERT(extdata[blen] == 0);  /* Application responsibility. */
52102                 data = extdata;
52103                 ((duk_hstring_external *) res)->extdata = extdata;
52104         } else
52105 #endif  /* DUK_USE_HSTRING_EXTDATA && DUK_USE_EXTSTR_INTERN_CHECK */
52106         {
52107                 duk_uint8_t *data_tmp;
52108
52109                 /* NUL terminate for convenient C access */
52110                 DUK_ASSERT(sizeof(duk_hstring) + blen + 1 > blen);  /* No wrap, limits ensure. */
52111                 res = (duk_hstring *) DUK_ALLOC(heap, sizeof(duk_hstring) + blen + 1);
52112                 if (DUK_UNLIKELY(res == NULL)) {
52113                         goto alloc_error;
52114                 }
52115                 duk_memzero(res, sizeof(duk_hstring));
52116 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
52117                 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
52118 #endif
52119                 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
52120
52121                 data_tmp = (duk_uint8_t *) (res + 1);
52122                 duk_memcpy(data_tmp, str, blen);
52123                 data_tmp[blen] = (duk_uint8_t) 0;
52124                 data = (const duk_uint8_t *) data_tmp;
52125         }
52126
52127         DUK_HSTRING_SET_BYTELEN(res, blen);
52128         DUK_HSTRING_SET_HASH(res, strhash);
52129
52130         DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res));
52131 #if defined(DUK_USE_HSTRING_ARRIDX)
52132         res->arridx = duk_js_to_arrayindex_string(data, blen);
52133         if (res->arridx != DUK_HSTRING_NO_ARRAY_INDEX) {
52134 #else
52135         dummy = duk_js_to_arrayindex_string(data, blen);
52136         if (dummy != DUK_HSTRING_NO_ARRAY_INDEX) {
52137 #endif
52138                 /* Array index strings cannot be symbol strings,
52139                  * and they're always pure ASCII so blen == clen.
52140                  */
52141                 DUK_HSTRING_SET_ARRIDX(res);
52142                 DUK_HSTRING_SET_ASCII(res);
52143                 DUK_ASSERT(duk_unicode_unvalidated_utf8_length(data, (duk_size_t) blen) == blen);
52144         } else {
52145                 /* Because 'data' is NUL-terminated, we don't need a
52146                  * blen > 0 check here.  For NUL (0x00) the symbol
52147                  * checks will be false.
52148                  */
52149                 if (DUK_UNLIKELY(data[0] >= 0x80U)) {
52150                         if (data[0] <= 0x81) {
52151                                 DUK_HSTRING_SET_SYMBOL(res);
52152                         } else if (data[0] == 0x82U || data[0] == 0xffU) {
52153                                 DUK_HSTRING_SET_HIDDEN(res);
52154                                 DUK_HSTRING_SET_SYMBOL(res);
52155                         }
52156                 }
52157
52158                 /* Using an explicit 'ASCII' flag has larger footprint (one call site
52159                  * only) but is quite useful for the case when there's no explicit
52160                  * 'clen' in duk_hstring.
52161                  *
52162                  * The flag is set lazily for RAM strings.
52163                  */
52164                 DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
52165
52166 #if defined(DUK_USE_HSTRING_LAZY_CLEN)
52167                 /* Charlen initialized to 0, updated on-the-fly. */
52168 #else
52169                 duk_hstring_init_charlen(res);  /* Also sets ASCII flag. */
52170 #endif
52171         }
52172
52173         DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, has_arridx=%ld, has_extdata=%ld",
52174                              (unsigned long) DUK_HSTRING_GET_HASH(res),
52175                              (long) DUK_HSTRING_GET_BYTELEN(res),
52176                              (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0),
52177                              (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0)));
52178
52179         DUK_ASSERT(res != NULL);
52180         return res;
52181
52182  alloc_error:
52183         return NULL;
52184 }
52185
52186 /*
52187  *  Grow strtable allocation in-place.
52188  */
52189
52190 #if defined(DUK__STRTAB_RESIZE_CHECK)
52191 DUK_LOCAL void duk__strtable_grow_inplace(duk_heap *heap) {
52192         duk_uint32_t new_st_size;
52193         duk_uint32_t old_st_size;
52194         duk_uint32_t i;
52195         duk_hstring *h;
52196         duk_hstring *next;
52197         duk_hstring *prev;
52198 #if defined(DUK_USE_STRTAB_PTRCOMP)
52199         duk_uint16_t *new_ptr;
52200         duk_uint16_t *new_ptr_high;
52201 #else
52202         duk_hstring **new_ptr;
52203         duk_hstring **new_ptr_high;
52204 #endif
52205
52206         DUK_DD(DUK_DDPRINT("grow in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2));
52207
52208         DUK_ASSERT(heap != NULL);
52209         DUK_ASSERT(heap->st_resizing == 1);
52210         DUK_ASSERT(heap->st_size >= 2);
52211         DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0);  /* 2^N */
52212         DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
52213
52214         DUK_STATS_INC(heap, stats_strtab_resize_grow);
52215
52216         new_st_size = heap->st_size << 1U;
52217         DUK_ASSERT(new_st_size > heap->st_size);  /* No overflow. */
52218
52219         /* Reallocate the strtable first and then work in-place to rehash
52220          * strings.  We don't need an indirect allocation here: even if GC
52221          * is triggered to satisfy the allocation, recursive strtable resize
52222          * is prevented by flags.  This is also why we don't need to use
52223          * DUK_REALLOC_INDIRECT().
52224          */
52225
52226 #if defined(DUK_USE_STRTAB_PTRCOMP)
52227         new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size);
52228 #else
52229         new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size);
52230 #endif
52231         if (DUK_UNLIKELY(new_ptr == NULL)) {
52232                 /* If realloc fails we can continue normally: the string table
52233                  * won't "fill up" although chains will gradually get longer.
52234                  * When string insertions continue, we'll quite soon try again
52235                  * with no special handling.
52236                  */
52237                 DUK_D(DUK_DPRINT("string table grow failed, ignoring"));
52238                 return;
52239         }
52240 #if defined(DUK_USE_STRTAB_PTRCOMP)
52241         heap->strtable16 = new_ptr;
52242 #else
52243         heap->strtable = new_ptr;
52244 #endif
52245
52246         /* Rehash a single bucket into two separate ones.  When we grow
52247          * by x2 the highest 'new' bit determines whether a string remains
52248          * in its old position (bit is 0) or goes to a new one (bit is 1).
52249          */
52250
52251         old_st_size = heap->st_size;
52252         new_ptr_high = new_ptr + old_st_size;
52253         for (i = 0; i < old_st_size; i++) {
52254                 duk_hstring *new_root;
52255                 duk_hstring *new_root_high;
52256
52257                 h = DUK__HEAPPTR_DEC16(heap, new_ptr[i]);
52258                 new_root = h;
52259                 new_root_high = NULL;
52260
52261                 prev = NULL;
52262                 while (h != NULL) {
52263                         duk_uint32_t mask;
52264
52265                         DUK_ASSERT((DUK_HSTRING_GET_HASH(h) & heap->st_mask) == i);
52266                         next = h->hdr.h_next;
52267
52268                         /* Example: if previous size was 256, previous mask is 0xFF
52269                          * and size is 0x100 which corresponds to the new bit that
52270                          * comes into play.
52271                          */
52272                         DUK_ASSERT(heap->st_mask == old_st_size - 1);
52273                         mask = old_st_size;
52274                         if (DUK_HSTRING_GET_HASH(h) & mask) {
52275                                 if (prev != NULL) {
52276                                         prev->hdr.h_next = h->hdr.h_next;
52277                                 } else {
52278                                         DUK_ASSERT(h == new_root);
52279                                         new_root = h->hdr.h_next;
52280                                 }
52281
52282                                 h->hdr.h_next = new_root_high;
52283                                 new_root_high = h;
52284                         } else {
52285                                 prev = h;
52286                         }
52287                         h = next;
52288                 }
52289
52290                 new_ptr[i] = DUK__HEAPPTR_ENC16(heap, new_root);
52291                 new_ptr_high[i] = DUK__HEAPPTR_ENC16(heap, new_root_high);
52292         }
52293
52294         heap->st_size = new_st_size;
52295         heap->st_mask = new_st_size - 1;
52296
52297 #if defined(DUK_USE_ASSERTIONS)
52298         duk__strtable_assert_checks(heap);
52299 #endif
52300 }
52301 #endif  /* DUK__STRTAB_RESIZE_CHECK */
52302
52303 /*
52304  *  Shrink strtable allocation in-place.
52305  */
52306
52307 #if defined(DUK__STRTAB_RESIZE_CHECK)
52308 DUK_LOCAL void duk__strtable_shrink_inplace(duk_heap *heap) {
52309         duk_uint32_t new_st_size;
52310         duk_uint32_t i;
52311         duk_hstring *h;
52312         duk_hstring *other;
52313         duk_hstring *root;
52314 #if defined(DUK_USE_STRTAB_PTRCOMP)
52315         duk_uint16_t *old_ptr;
52316         duk_uint16_t *old_ptr_high;
52317         duk_uint16_t *new_ptr;
52318 #else
52319         duk_hstring **old_ptr;
52320         duk_hstring **old_ptr_high;
52321         duk_hstring **new_ptr;
52322 #endif
52323
52324         DUK_DD(DUK_DDPRINT("shrink in-place: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2));
52325
52326         DUK_ASSERT(heap != NULL);
52327         DUK_ASSERT(heap->st_resizing == 1);
52328         DUK_ASSERT(heap->st_size >= 2);
52329         DUK_ASSERT((heap->st_size & (heap->st_size - 1)) == 0);  /* 2^N */
52330         DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
52331
52332         DUK_STATS_INC(heap, stats_strtab_resize_shrink);
52333
52334         new_st_size = heap->st_size >> 1U;
52335
52336         /* Combine two buckets into a single one.  When we shrink, one hash
52337          * bit (highest) disappears.
52338          */
52339         old_ptr = DUK__GET_STRTABLE(heap);
52340         old_ptr_high = old_ptr + new_st_size;
52341         for (i = 0; i < new_st_size; i++) {
52342                 h = DUK__HEAPPTR_DEC16(heap, old_ptr[i]);
52343                 other = DUK__HEAPPTR_DEC16(heap, old_ptr_high[i]);
52344
52345                 if (h == NULL) {
52346                         /* First chain is empty, so use second one as is. */
52347                         root = other;
52348                 } else {
52349                         /* Find end of first chain, and link in the second. */
52350                         root = h;
52351                         while (h->hdr.h_next != NULL) {
52352                                 h = h->hdr.h_next;
52353                         }
52354                         h->hdr.h_next = other;
52355                 }
52356
52357                 old_ptr[i] = DUK__HEAPPTR_ENC16(heap, root);
52358         }
52359
52360         heap->st_size = new_st_size;
52361         heap->st_mask = new_st_size - 1;
52362
52363         /* The strtable is now consistent and we can realloc safely.  Even
52364          * if side effects cause string interning or removal the strtable
52365          * updates are safe.  Recursive resize has been prevented by caller.
52366          * This is also why we don't need to use DUK_REALLOC_INDIRECT().
52367          *
52368          * We assume a realloc() to a smaller size is guaranteed to succeed.
52369          * It would be relatively straightforward to handle the error by
52370          * essentially performing a "grow" step to recover.
52371          */
52372
52373 #if defined(DUK_USE_STRTAB_PTRCOMP)
52374         new_ptr = (duk_uint16_t *) DUK_REALLOC(heap, heap->strtable16, sizeof(duk_uint16_t) * new_st_size);
52375         DUK_ASSERT(new_ptr != NULL);
52376         heap->strtable16 = new_ptr;
52377 #else
52378         new_ptr = (duk_hstring **) DUK_REALLOC(heap, heap->strtable, sizeof(duk_hstring *) * new_st_size);
52379         DUK_ASSERT(new_ptr != NULL);
52380         heap->strtable = new_ptr;
52381 #endif
52382
52383 #if defined(DUK_USE_ASSERTIONS)
52384         duk__strtable_assert_checks(heap);
52385 #endif
52386 }
52387 #endif  /* DUK__STRTAB_RESIZE_CHECK */
52388
52389 /*
52390  *  Grow/shrink check.
52391  */
52392
52393 #if defined(DUK__STRTAB_RESIZE_CHECK)
52394 DUK_LOCAL DUK_COLD DUK_NOINLINE void duk__strtable_resize_check(duk_heap *heap) {
52395         duk_uint32_t load_factor;  /* fixed point */
52396
52397         DUK_ASSERT(heap != NULL);
52398 #if defined(DUK_USE_STRTAB_PTRCOMP)
52399         DUK_ASSERT(heap->strtable16 != NULL);
52400 #else
52401         DUK_ASSERT(heap->strtable != NULL);
52402 #endif
52403
52404         DUK_STATS_INC(heap, stats_strtab_resize_check);
52405
52406         /* Prevent recursive resizing. */
52407         if (DUK_UNLIKELY(heap->st_resizing != 0U)) {
52408                 DUK_D(DUK_DPRINT("prevent recursive strtable resize"));
52409                 return;
52410         }
52411
52412         heap->st_resizing = 1;
52413
52414         DUK_ASSERT(heap->st_size >= 16U);
52415         DUK_ASSERT((heap->st_size >> 4U) >= 1);
52416         load_factor = heap->st_count / (heap->st_size >> 4U);
52417
52418         DUK_DD(DUK_DDPRINT("resize check string table: size=%lu, count=%lu, load_factor=%lu (fixed point .4; float %lf)",
52419                            (unsigned long) heap->st_size, (unsigned long) heap->st_count,
52420                            (unsigned long) load_factor,
52421                            (double) heap->st_count / (double) heap->st_size));
52422
52423         if (load_factor >= DUK_USE_STRTAB_GROW_LIMIT) {
52424                 if (heap->st_size >= DUK_USE_STRTAB_MAXSIZE) {
52425                         DUK_DD(DUK_DDPRINT("want to grow strtable (based on load factor) but already maximum size"));
52426                 } else {
52427                         DUK_D(DUK_DPRINT("grow string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size * 2));
52428 #if defined(DUK_USE_DEBUG)
52429                         duk_heap_strtable_dump(heap);
52430 #endif
52431                         duk__strtable_grow_inplace(heap);
52432                 }
52433         } else if (load_factor <= DUK_USE_STRTAB_SHRINK_LIMIT) {
52434                 if (heap->st_size <= DUK_USE_STRTAB_MINSIZE) {
52435                         DUK_DD(DUK_DDPRINT("want to shrink strtable (based on load factor) but already minimum size"));
52436                 } else {
52437                         DUK_D(DUK_DPRINT("shrink string table: %lu -> %lu", (unsigned long) heap->st_size, (unsigned long) heap->st_size / 2));
52438 #if defined(DUK_USE_DEBUG)
52439                         duk_heap_strtable_dump(heap);
52440 #endif
52441                         duk__strtable_shrink_inplace(heap);
52442                 }
52443         } else {
52444                 DUK_DD(DUK_DDPRINT("no need for strtable resize"));
52445         }
52446
52447         heap->st_resizing = 0;
52448 }
52449 #endif  /* DUK__STRTAB_RESIZE_CHECK */
52450
52451 /*
52452  *  Torture grow/shrink: unconditionally grow and shrink back.
52453  */
52454
52455 #if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK)
52456 DUK_LOCAL void duk__strtable_resize_torture(duk_heap *heap) {
52457         duk_uint32_t old_st_size;
52458
52459         DUK_ASSERT(heap != NULL);
52460
52461         old_st_size = heap->st_size;
52462         if (old_st_size >= DUK_USE_STRTAB_MAXSIZE) {
52463                 return;
52464         }
52465
52466         heap->st_resizing = 1;
52467         duk__strtable_grow_inplace(heap);
52468         if (heap->st_size > old_st_size) {
52469                 duk__strtable_shrink_inplace(heap);
52470         }
52471         heap->st_resizing = 0;
52472 }
52473 #endif  /* DUK_USE_STRTAB_TORTURE && DUK__STRTAB_RESIZE_CHECK */
52474
52475 /*
52476  *  Raw intern; string already checked not to be present.
52477  */
52478
52479 DUK_LOCAL duk_hstring *duk__strtable_do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
52480         duk_hstring *res;
52481         const duk_uint8_t *extdata;
52482 #if defined(DUK_USE_STRTAB_PTRCOMP)
52483         duk_uint16_t *slot;
52484 #else
52485         duk_hstring **slot;
52486 #endif
52487
52488         DUK_DDD(DUK_DDDPRINT("do_intern: heap=%p, str=%p, blen=%lu, strhash=%lx, st_size=%lu, st_count=%lu, load=%lf",
52489                              (void *) heap, (const void *) str, (unsigned long) blen, (unsigned long) strhash,
52490                              (unsigned long) heap->st_size, (unsigned long) heap->st_count,
52491                              (double) heap->st_count / (double) heap->st_size));
52492
52493         DUK_ASSERT(heap != NULL);
52494
52495         /* Prevent any side effects on the string table and the caller provided
52496          * str/blen arguments while interning is in progress.  For example, if
52497          * the caller provided str/blen from a dynamic buffer, a finalizer
52498          * might resize or modify that dynamic buffer, invalidating the call
52499          * arguments.
52500          *
52501          * While finalizers must be prevented, mark-and-sweep itself is fine.
52502          * Recursive string table resize is prevented explicitly here.
52503          */
52504
52505         heap->pf_prevent_count++;
52506         DUK_ASSERT(heap->pf_prevent_count != 0);  /* Wrap. */
52507
52508 #if defined(DUK_USE_STRTAB_TORTURE) && defined(DUK__STRTAB_RESIZE_CHECK)
52509         duk__strtable_resize_torture(heap);
52510 #endif
52511
52512         /* String table grow/shrink check.  Because of chaining (and no
52513          * accumulation issues as with hash probe chains and DELETED
52514          * markers) there's never a mandatory need to resize right now.
52515          * Check for the resize only periodically, based on st_count
52516          * bit pattern.  Because string table removal doesn't do a shrink
52517          * check, we do that also here.
52518          *
52519          * Do the resize and possible grow/shrink before the new duk_hstring
52520          * has been allocated.  Otherwise we may trigger a GC when the result
52521          * duk_hstring is not yet strongly referenced.
52522          */
52523
52524 #if defined(DUK__STRTAB_RESIZE_CHECK)
52525         if (DUK_UNLIKELY((heap->st_count & DUK_USE_STRTAB_RESIZE_CHECK_MASK) == 0)) {
52526                 duk__strtable_resize_check(heap);
52527         }
52528 #endif
52529
52530         /* External string check (low memory optimization). */
52531
52532 #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
52533         extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen);
52534 #else
52535         extdata = (const duk_uint8_t *) NULL;
52536 #endif
52537
52538         /* Allocate and initialize string, not yet linked.  This may cause a
52539          * GC which may cause other strings to be interned and inserted into
52540          * the string table before we insert our string.  Finalizer execution
52541          * is disabled intentionally to avoid a finalizer from e.g. resizing
52542          * a buffer used as a data area for 'str'.
52543          */
52544
52545         res = duk__strtable_alloc_hstring(heap, str, blen, strhash, extdata);
52546
52547         /* Allow side effects again: GC must be avoided until duk_hstring
52548          * result (if successful) has been INCREF'd.
52549          */
52550         DUK_ASSERT(heap->pf_prevent_count > 0);
52551         heap->pf_prevent_count--;
52552
52553         /* Alloc error handling. */
52554
52555         if (DUK_UNLIKELY(res == NULL)) {
52556 #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
52557                 if (extdata != NULL) {
52558                         DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) extdata);
52559                 }
52560 #endif
52561                 return NULL;
52562         }
52563
52564         /* Insert into string table. */
52565
52566 #if defined(DUK_USE_STRTAB_PTRCOMP)
52567         slot = heap->strtable16 + (strhash & heap->st_mask);
52568 #else
52569         slot = heap->strtable + (strhash & heap->st_mask);
52570 #endif
52571         DUK_ASSERT(res->hdr.h_next == NULL);  /* This is the case now, but unnecessary zeroing/NULLing. */
52572         res->hdr.h_next = DUK__HEAPPTR_DEC16(heap, *slot);
52573         *slot = DUK__HEAPPTR_ENC16(heap, res);
52574
52575         /* Update string count only for successful inserts. */
52576
52577 #if defined(DUK__STRTAB_RESIZE_CHECK)
52578         heap->st_count++;
52579 #endif
52580
52581         /* The duk_hstring is in the string table but is not yet strongly
52582          * reachable.  Calling code MUST NOT make any allocations or other
52583          * side effects before the duk_hstring has been INCREF'd and made
52584          * reachable.
52585          */
52586
52587         return res;
52588 }
52589
52590 /*
52591  *  Intern a string from str/blen, returning either an existing duk_hstring
52592  *  or adding a new one into the string table.  The input string does -not-
52593  *  need to be NUL terminated.
52594  *
52595  *  The input 'str' argument may point to a Duktape managed data area such as
52596  *  the data area of a dynamic buffer.  It's crucial to avoid any side effects
52597  *  that might affect the data area (e.g. resize the dynamic buffer, or write
52598  *  to the buffer) before the string is fully interned.
52599  */
52600
52601 #if defined(DUK_USE_ROM_STRINGS)
52602 DUK_LOCAL duk_hstring *duk__strtab_romstring_lookup(duk_heap *heap, const duk_uint8_t *str, duk_size_t blen, duk_uint32_t strhash) {
52603         duk_size_t lookup_hash;
52604         duk_hstring *curr;
52605
52606         DUK_ASSERT(heap != NULL);
52607         DUK_UNREF(heap);
52608
52609         lookup_hash = (blen << 4);
52610         if (blen > 0) {
52611                 lookup_hash += str[0];
52612         }
52613         lookup_hash &= 0xff;
52614
52615         curr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_lookup[lookup_hash]);
52616         while (curr != NULL) {
52617                 /* Unsafe memcmp() because for zero blen, str may be NULL. */
52618                 if (strhash == DUK_HSTRING_GET_HASH(curr) &&
52619                     blen == DUK_HSTRING_GET_BYTELEN(curr) &&
52620                     duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(curr), blen) == 0) {
52621                         DUK_DDD(DUK_DDDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
52622                                              curr, (unsigned long) strhash, (unsigned long) DUK_HSTRING_GET_HASH(curr)));
52623                         return curr;
52624                 }
52625                 curr = curr->hdr.h_next;
52626         }
52627
52628         return NULL;
52629 }
52630 #endif  /* DUK_USE_ROM_STRINGS */
52631
52632 DUK_INTERNAL duk_hstring *duk_heap_strtable_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
52633         duk_uint32_t strhash;
52634         duk_hstring *h;
52635
52636         DUK_DDD(DUK_DDDPRINT("intern check: heap=%p, str=%p, blen=%lu", (void *) heap, (const void *) str, (unsigned long) blen));
52637
52638         /* Preliminaries. */
52639
52640         /* XXX: maybe just require 'str != NULL' even for zero size? */
52641         DUK_ASSERT(heap != NULL);
52642         DUK_ASSERT(blen == 0 || str != NULL);
52643         DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN);  /* Caller is responsible for ensuring this. */
52644         strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);
52645
52646         /* String table lookup. */
52647
52648         DUK_ASSERT(DUK__GET_STRTABLE(heap) != NULL);
52649         DUK_ASSERT(heap->st_size > 0);
52650         DUK_ASSERT(heap->st_size == heap->st_mask + 1);
52651 #if defined(DUK_USE_STRTAB_PTRCOMP)
52652         h = DUK__HEAPPTR_DEC16(heap, heap->strtable16[strhash & heap->st_mask]);
52653 #else
52654         h = heap->strtable[strhash & heap->st_mask];
52655 #endif
52656         while (h != NULL) {
52657                 if (DUK_HSTRING_GET_HASH(h) == strhash &&
52658                     DUK_HSTRING_GET_BYTELEN(h) == blen &&
52659                     duk_memcmp_unsafe((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
52660                         /* Found existing entry. */
52661                         DUK_STATS_INC(heap, stats_strtab_intern_hit);
52662                         return h;
52663                 }
52664                 h = h->hdr.h_next;
52665         }
52666
52667         /* ROM table lookup.  Because this lookup is slower, do it only after
52668          * RAM lookup.  This works because no ROM string is ever interned into
52669          * the RAM string table.
52670          */
52671
52672 #if defined(DUK_USE_ROM_STRINGS)
52673         h = duk__strtab_romstring_lookup(heap, str, blen, strhash);
52674         if (h != NULL) {
52675                 DUK_STATS_INC(heap, stats_strtab_intern_hit);
52676                 return h;
52677         }
52678 #endif
52679
52680         /* Not found in string table; insert. */
52681
52682         DUK_STATS_INC(heap, stats_strtab_intern_miss);
52683         h = duk__strtable_do_intern(heap, str, blen, strhash);
52684         return h;  /* may be NULL */
52685 }
52686
52687 /*
52688  *  Intern a string from u32.
52689  */
52690
52691 /* XXX: Could arrange some special handling because we know that the result
52692  * will have an arridx flag and an ASCII flag, won't need a clen check, etc.
52693  */
52694
52695 DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32(duk_heap *heap, duk_uint32_t val) {
52696         duk_uint8_t buf[DUK__STRTAB_U32_MAX_STRLEN];
52697         duk_uint8_t *p;
52698
52699         DUK_ASSERT(heap != NULL);
52700
52701         /* This is smaller and faster than a %lu sprintf. */
52702         p = buf + sizeof(buf);
52703         do {
52704                 p--;
52705                 *p = duk_lc_digits[val % 10];
52706                 val = val / 10;
52707         } while (val != 0);  /* For val == 0, emit exactly one '0'. */
52708         DUK_ASSERT(p >= buf);
52709
52710         return duk_heap_strtable_intern(heap, (const duk_uint8_t *) p, (duk_uint32_t) ((buf + sizeof(buf)) - p));
52711 }
52712
52713 /*
52714  *  Checked convenience variants.
52715  *
52716  *  XXX: Because the main use case is for the checked variants, make them the
52717  *  main functionality and provide a safe variant separately (it is only needed
52718  *  during heap init).  The problem with that is that longjmp state and error
52719  *  creation must already be possible to throw.
52720  */
52721
52722 DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
52723         duk_hstring *res;
52724
52725         DUK_ASSERT(thr != NULL);
52726         DUK_ASSERT(thr->heap != NULL);
52727         DUK_ASSERT(blen == 0 || str != NULL);
52728
52729         res = duk_heap_strtable_intern(thr->heap, str, blen);
52730         if (DUK_UNLIKELY(res == NULL)) {
52731                 DUK_ERROR_ALLOC_FAILED(thr);
52732                 DUK_WO_NORETURN(return NULL;);
52733         }
52734         return res;
52735 }
52736
52737 #if defined(DUK_USE_LITCACHE_SIZE)
52738 DUK_LOCAL duk_uint_t duk__strtable_litcache_key(const duk_uint8_t *str, duk_uint32_t blen) {
52739         duk_uintptr_t key;
52740
52741         DUK_ASSERT(DUK_USE_LITCACHE_SIZE > 0);
52742         DUK_ASSERT(DUK_IS_POWER_OF_TWO((duk_uint_t) DUK_USE_LITCACHE_SIZE));
52743
52744         key = (duk_uintptr_t) blen ^ (duk_uintptr_t) str;
52745         key &= (duk_uintptr_t) (DUK_USE_LITCACHE_SIZE - 1);  /* Assumes size is power of 2. */
52746         /* Due to masking, cast is in 32-bit range. */
52747         DUK_ASSERT(key <= DUK_UINT_MAX);
52748         return (duk_uint_t) key;
52749 }
52750
52751 DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_literal_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
52752         duk_uint_t key;
52753         duk_litcache_entry *ent;
52754         duk_hstring *h;
52755
52756         /* Fast path check: literal exists in literal cache. */
52757         key = duk__strtable_litcache_key(str, blen);
52758         ent = thr->heap->litcache + key;
52759         if (ent->addr == str) {
52760                 DUK_DD(DUK_DDPRINT("intern check for cached, pinned literal: str=%p, blen=%ld -> duk_hstring %!O",
52761                                    (const void *) str, (long) blen, (duk_heaphdr *) ent->h));
52762                 DUK_ASSERT(ent->h != NULL);
52763                 DUK_ASSERT(DUK_HSTRING_HAS_PINNED_LITERAL(ent->h));
52764                 DUK_STATS_INC(thr->heap, stats_strtab_litcache_hit);
52765                 return ent->h;
52766         }
52767
52768         /* Intern and update (overwrite) cache entry. */
52769         h = duk_heap_strtable_intern_checked(thr, str, blen);
52770         ent->addr = str;
52771         ent->h = h;
52772         DUK_STATS_INC(thr->heap, stats_strtab_litcache_miss);
52773
52774         /* Pin the duk_hstring until the next mark-and-sweep.  This means
52775          * litcache entries don't need to be invalidated until the next
52776          * mark-and-sweep as their target duk_hstring is not freed before
52777          * the mark-and-sweep happens.  The pin remains even if the literal
52778          * cache entry is overwritten, and is still useful to avoid string
52779          * table traffic.
52780          */
52781         if (!DUK_HSTRING_HAS_PINNED_LITERAL(h)) {
52782                 DUK_DD(DUK_DDPRINT("pin duk_hstring because it is a literal: %!O", (duk_heaphdr *) h));
52783                 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
52784                 DUK_HSTRING_INCREF(thr, h);
52785                 DUK_HSTRING_SET_PINNED_LITERAL(h);
52786                 DUK_STATS_INC(thr->heap, stats_strtab_litcache_pin);
52787         }
52788
52789         return h;
52790 }
52791 #endif  /* DUK_USE_LITCACHE_SIZE */
52792
52793 DUK_INTERNAL duk_hstring *duk_heap_strtable_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
52794         duk_hstring *res;
52795
52796         DUK_ASSERT(thr != NULL);
52797         DUK_ASSERT(thr->heap != NULL);
52798
52799         res = duk_heap_strtable_intern_u32(thr->heap, val);
52800         if (DUK_UNLIKELY(res == NULL)) {
52801                 DUK_ERROR_ALLOC_FAILED(thr);
52802                 DUK_WO_NORETURN(return NULL;);
52803         }
52804         return res;
52805 }
52806
52807 /*
52808  *  Remove (unlink) a string from the string table.
52809  *
52810  *  Just unlinks the duk_hstring, leaving link pointers as garbage.
52811  *  Caller must free the string itself.
52812  */
52813
52814 #if defined(DUK_USE_REFERENCE_COUNTING)
52815 /* Unlink without a 'prev' pointer. */
52816 DUK_INTERNAL void duk_heap_strtable_unlink(duk_heap *heap, duk_hstring *h) {
52817 #if defined(DUK_USE_STRTAB_PTRCOMP)
52818         duk_uint16_t *slot;
52819 #else
52820         duk_hstring **slot;
52821 #endif
52822         duk_hstring *other;
52823         duk_hstring *prev;
52824
52825         DUK_DDD(DUK_DDDPRINT("remove: heap=%p, h=%p, blen=%lu, strhash=%lx",
52826                              (void *) heap, (void *) h,
52827                              (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0),
52828                              (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0)));
52829
52830         DUK_ASSERT(heap != NULL);
52831         DUK_ASSERT(h != NULL);
52832
52833 #if defined(DUK__STRTAB_RESIZE_CHECK)
52834         DUK_ASSERT(heap->st_count > 0);
52835         heap->st_count--;
52836 #endif
52837
52838 #if defined(DUK_USE_STRTAB_PTRCOMP)
52839         slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
52840 #else
52841         slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
52842 #endif
52843         other = DUK__HEAPPTR_DEC16(heap, *slot);
52844         DUK_ASSERT(other != NULL);  /* At least argument string is in the chain. */
52845
52846         prev = NULL;
52847         while (other != h) {
52848                 prev = other;
52849                 other = other->hdr.h_next;
52850                 DUK_ASSERT(other != NULL);  /* We'll eventually find 'h'. */
52851         }
52852         if (prev != NULL) {
52853                 /* Middle of list. */
52854                 prev->hdr.h_next = h->hdr.h_next;
52855         } else {
52856                 /* Head of list. */
52857                 *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next);
52858         }
52859
52860         /* There's no resize check on a string free.  The next string
52861          * intern will do one.
52862          */
52863 }
52864 #endif  /* DUK_USE_REFERENCE_COUNTING */
52865
52866 /* Unlink with a 'prev' pointer. */
52867 DUK_INTERNAL void duk_heap_strtable_unlink_prev(duk_heap *heap, duk_hstring *h, duk_hstring *prev) {
52868 #if defined(DUK_USE_STRTAB_PTRCOMP)
52869         duk_uint16_t *slot;
52870 #else
52871         duk_hstring **slot;
52872 #endif
52873
52874         DUK_DDD(DUK_DDDPRINT("remove: heap=%p, prev=%p, h=%p, blen=%lu, strhash=%lx",
52875                              (void *) heap, (void *) prev, (void *) h,
52876                              (unsigned long) (h != NULL ? DUK_HSTRING_GET_BYTELEN(h) : 0),
52877                              (unsigned long) (h != NULL ? DUK_HSTRING_GET_HASH(h) : 0)));
52878
52879         DUK_ASSERT(heap != NULL);
52880         DUK_ASSERT(h != NULL);
52881         DUK_ASSERT(prev == NULL || prev->hdr.h_next == h);
52882
52883 #if defined(DUK__STRTAB_RESIZE_CHECK)
52884         DUK_ASSERT(heap->st_count > 0);
52885         heap->st_count--;
52886 #endif
52887
52888         if (prev != NULL) {
52889                 /* Middle of list. */
52890                 prev->hdr.h_next = h->hdr.h_next;
52891         } else {
52892                 /* Head of list. */
52893 #if defined(DUK_USE_STRTAB_PTRCOMP)
52894                 slot = heap->strtable16 + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
52895 #else
52896                 slot = heap->strtable + (DUK_HSTRING_GET_HASH(h) & heap->st_mask);
52897 #endif
52898                 DUK_ASSERT(DUK__HEAPPTR_DEC16(heap, *slot) == h);
52899                 *slot = DUK__HEAPPTR_ENC16(heap, h->hdr.h_next);
52900         }
52901 }
52902
52903 /*
52904  *  Force string table resize check in mark-and-sweep.
52905  */
52906
52907 DUK_INTERNAL void duk_heap_strtable_force_resize(duk_heap *heap) {
52908         /* Does only one grow/shrink step if needed.  The heap->st_resizing
52909          * flag protects against recursive resizing.
52910          */
52911
52912         DUK_ASSERT(heap != NULL);
52913         DUK_UNREF(heap);
52914
52915 #if defined(DUK__STRTAB_RESIZE_CHECK)
52916 #if defined(DUK_USE_STRTAB_PTRCOMP)
52917         if (heap->strtable16 != NULL) {
52918 #else
52919         if (heap->strtable != NULL) {
52920 #endif
52921                 duk__strtable_resize_check(heap);
52922         }
52923 #endif
52924 }
52925
52926 /*
52927  *  Free strings in the string table and the string table itself.
52928  */
52929
52930 DUK_INTERNAL void duk_heap_strtable_free(duk_heap *heap) {
52931 #if defined(DUK_USE_STRTAB_PTRCOMP)
52932         duk_uint16_t *strtable;
52933         duk_uint16_t *st;
52934 #else
52935         duk_hstring **strtable;
52936         duk_hstring **st;
52937 #endif
52938         duk_hstring *h;
52939
52940         DUK_ASSERT(heap != NULL);
52941
52942 #if defined(DUK_USE_ASSERTIONS)
52943         duk__strtable_assert_checks(heap);
52944 #endif
52945
52946         /* Strtable can be NULL if heap init fails.  However, in that case
52947          * heap->st_size is 0, so strtable == strtable_end and we skip the
52948          * loop without a special check.
52949          */
52950         strtable = DUK__GET_STRTABLE(heap);
52951         st = strtable + heap->st_size;
52952         DUK_ASSERT(strtable != NULL || heap->st_size == 0);
52953
52954         while (strtable != st) {
52955                 --st;
52956                 h = DUK__HEAPPTR_DEC16(heap, *st);
52957                 while (h) {
52958                         duk_hstring *h_next;
52959                         h_next = h->hdr.h_next;
52960
52961                         /* Strings may have inner refs (extdata) in some cases. */
52962                         duk_free_hstring(heap, h);
52963
52964                         h = h_next;
52965                 }
52966         }
52967
52968         DUK_FREE(heap, strtable);
52969 }
52970
52971 /* automatic undefs */
52972 #undef DUK__GET_STRTABLE
52973 #undef DUK__HEAPPTR_DEC16
52974 #undef DUK__HEAPPTR_ENC16
52975 #undef DUK__STRTAB_U32_MAX_STRLEN
52976 #line 1 "duk_hobject_alloc.c"
52977 /*
52978  *  Hobject allocation.
52979  *
52980  *  Provides primitive allocation functions for all object types (plain object,
52981  *  compiled function, native function, thread).  The object return is not yet
52982  *  in "heap allocated" list and has a refcount of zero, so caller must careful.
52983  */
52984
52985 /* XXX: In most cases there's no need for plain allocation without pushing
52986  * to the value stack.  Maybe rework contract?
52987  */
52988
52989 /* #include duk_internal.h -> already included */
52990
52991 /*
52992  *  Helpers.
52993  */
52994
52995 DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_uint_t hobject_flags, duk_hobject *obj) {
52996         DUK_ASSERT(obj != NULL);
52997         /* Zeroed by caller. */
52998
52999         obj->hdr.h_flags = hobject_flags | DUK_HTYPE_OBJECT;
53000         DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(&obj->hdr) == DUK_HTYPE_OBJECT);  /* Assume zero shift. */
53001
53002 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
53003         DUK_HOBJECT_SET_PROTOTYPE(heap, obj, NULL);
53004         DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
53005 #endif
53006 #if defined(DUK_USE_HEAPPTR16)
53007         /* Zero encoded pointer is required to match NULL. */
53008         DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
53009 #if defined(DUK_USE_DOUBLE_LINKED_HEAP)
53010         DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
53011 #endif
53012 #endif
53013         DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr);
53014         DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
53015
53016         /* obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
53017          * with this properly.  This is intentional: empty objects consume a minimum
53018          * amount of memory.  Further, an initial allocation might fail and cause
53019          * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
53020          */
53021 }
53022
53023 DUK_LOCAL void *duk__hobject_alloc_init(duk_hthread *thr, duk_uint_t hobject_flags, duk_size_t size) {
53024         void *res;
53025
53026         res = (void *) DUK_ALLOC_CHECKED_ZEROED(thr, size);
53027         DUK_ASSERT(res != NULL);
53028         duk__init_object_parts(thr->heap, hobject_flags, (duk_hobject *) res);
53029         return res;
53030 }
53031
53032 /*
53033  *  Allocate an duk_hobject.
53034  *
53035  *  The allocated object has no allocation for properties; the caller may
53036  *  want to force a resize if a desired size is known.
53037  *
53038  *  The allocated object has zero reference count and is not reachable.
53039  *  The caller MUST make the object reachable and increase its reference
53040  *  count before invoking any operation that might require memory allocation.
53041  */
53042
53043 DUK_INTERNAL duk_hobject *duk_hobject_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) {
53044         duk_hobject *res;
53045
53046         DUK_ASSERT(heap != NULL);
53047
53048         /* different memory layout, alloc size, and init */
53049         DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0);
53050         DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0);
53051         DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_BOUNDFUNC) == 0);
53052
53053         res = (duk_hobject *) DUK_ALLOC_ZEROED(heap, sizeof(duk_hobject));
53054         if (DUK_UNLIKELY(res == NULL)) {
53055                 return NULL;
53056         }
53057         DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res));
53058
53059         duk__init_object_parts(heap, hobject_flags, res);
53060
53061         DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(res));
53062         return res;
53063 }
53064
53065 DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53066         duk_hobject *res;
53067
53068         res = (duk_hobject *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobject));
53069         return res;
53070 }
53071
53072 DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53073         duk_hcompfunc *res;
53074
53075         res = (duk_hcompfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hcompfunc));
53076 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
53077 #if defined(DUK_USE_HEAPPTR16)
53078         /* NULL pointer is required to encode to zero, so memset is enough. */
53079 #else
53080         res->data = NULL;
53081         res->funcs = NULL;
53082         res->bytecode = NULL;
53083 #endif
53084         res->lex_env = NULL;
53085         res->var_env = NULL;
53086 #endif
53087
53088         return res;
53089 }
53090
53091 DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53092         duk_hnatfunc *res;
53093
53094         res = (duk_hnatfunc *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hnatfunc));
53095 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
53096         res->func = NULL;
53097 #endif
53098
53099         return res;
53100 }
53101
53102 DUK_INTERNAL duk_hboundfunc *duk_hboundfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
53103         duk_hboundfunc *res;
53104
53105         res = (duk_hboundfunc *) DUK_ALLOC(heap, sizeof(duk_hboundfunc));
53106         if (!res) {
53107                 return NULL;
53108         }
53109         duk_memzero(res, sizeof(duk_hboundfunc));
53110
53111         duk__init_object_parts(heap, hobject_flags, &res->obj);
53112
53113         DUK_TVAL_SET_UNDEFINED(&res->target);
53114         DUK_TVAL_SET_UNDEFINED(&res->this_binding);
53115
53116 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
53117         res->args = NULL;
53118 #endif
53119
53120         return res;
53121 }
53122
53123 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
53124 DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53125         duk_hbufobj *res;
53126
53127         res = (duk_hbufobj *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hbufobj));
53128 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
53129         res->buf = NULL;
53130         res->buf_prop = NULL;
53131 #endif
53132
53133         DUK_ASSERT_HBUFOBJ_VALID(res);
53134         return res;
53135 }
53136 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
53137
53138 /* Allocate a new thread.
53139  *
53140  * Leaves the built-ins array uninitialized.  The caller must either
53141  * initialize a new global context or share existing built-ins from
53142  * another thread.
53143  */
53144 DUK_INTERNAL duk_hthread *duk_hthread_alloc_unchecked(duk_heap *heap, duk_uint_t hobject_flags) {
53145         duk_hthread *res;
53146
53147         res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
53148         if (DUK_UNLIKELY(res == NULL)) {
53149                 return NULL;
53150         }
53151         duk_memzero(res, sizeof(duk_hthread));
53152
53153         duk__init_object_parts(heap, hobject_flags, &res->obj);
53154
53155 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
53156         res->ptr_curr_pc = NULL;
53157         res->heap = NULL;
53158         res->valstack = NULL;
53159         res->valstack_end = NULL;
53160         res->valstack_alloc_end = NULL;
53161         res->valstack_bottom = NULL;
53162         res->valstack_top = NULL;
53163         res->callstack_curr = NULL;
53164         res->resumer = NULL;
53165         res->compile_ctx = NULL,
53166 #if defined(DUK_USE_HEAPPTR16)
53167         res->strs16 = NULL;
53168 #else
53169         res->strs = NULL;
53170 #endif
53171         {
53172                 duk_small_uint_t i;
53173                 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
53174                         res->builtins[i] = NULL;
53175                 }
53176         }
53177 #endif
53178         /* When nothing is running, API calls are in non-strict mode. */
53179         DUK_ASSERT(res->strict == 0);
53180
53181         res->heap = heap;
53182
53183         /* XXX: Any reason not to merge duk_hthread_alloc.c here? */
53184         return res;
53185 }
53186
53187 DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53188         duk_hthread *res;
53189
53190         res = duk_hthread_alloc_unchecked(thr->heap, hobject_flags);
53191         if (res == NULL) {
53192                 DUK_ERROR_ALLOC_FAILED(thr);
53193                 DUK_WO_NORETURN(return NULL;);
53194         }
53195         return res;
53196 }
53197
53198 DUK_INTERNAL duk_harray *duk_harray_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53199         duk_harray *res;
53200
53201         res = (duk_harray *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_harray));
53202
53203         DUK_ASSERT(res->length == 0);
53204
53205         return res;
53206 }
53207
53208 DUK_INTERNAL duk_hdecenv *duk_hdecenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53209         duk_hdecenv *res;
53210
53211         res = (duk_hdecenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hdecenv));
53212 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
53213         res->thread = NULL;
53214         res->varmap = NULL;
53215 #endif
53216
53217         DUK_ASSERT(res->thread == NULL);
53218         DUK_ASSERT(res->varmap == NULL);
53219         DUK_ASSERT(res->regbase_byteoff == 0);
53220
53221         return res;
53222 }
53223
53224 DUK_INTERNAL duk_hobjenv *duk_hobjenv_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53225         duk_hobjenv *res;
53226
53227         res = (duk_hobjenv *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hobjenv));
53228 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
53229         res->target = NULL;
53230 #endif
53231
53232         DUK_ASSERT(res->target == NULL);
53233
53234         return res;
53235 }
53236
53237 DUK_INTERNAL duk_hproxy *duk_hproxy_alloc(duk_hthread *thr, duk_uint_t hobject_flags) {
53238         duk_hproxy *res;
53239
53240         res = (duk_hproxy *) duk__hobject_alloc_init(thr, hobject_flags, sizeof(duk_hproxy));
53241
53242         /* Leave ->target and ->handler uninitialized, as caller will always
53243          * explicitly initialize them before any side effects are possible.
53244          */
53245
53246         return res;
53247 }
53248 #line 1 "duk_hobject_enum.c"
53249 /*
53250  *  Object enumeration support.
53251  *
53252  *  Creates an internal enumeration state object to be used e.g. with for-in
53253  *  enumeration.  The state object contains a snapshot of target object keys
53254  *  and internal control state for enumeration.  Enumerator flags allow caller
53255  *  to e.g. request internal/non-enumerable properties, and to enumerate only
53256  *  "own" properties.
53257  *
53258  *  Also creates the result value for e.g. Object.keys() based on the same
53259  *  internal structure.
53260  *
53261  *  This snapshot-based enumeration approach is used to simplify enumeration:
53262  *  non-snapshot-based approaches are difficult to reconcile with mutating
53263  *  the enumeration target, running multiple long-lived enumerators at the
53264  *  same time, garbage collection details, etc.  The downside is that the
53265  *  enumerator object is memory inefficient especially for iterating arrays.
53266  */
53267
53268 /* #include duk_internal.h -> already included */
53269
53270 /* XXX: identify enumeration target with an object index (not top of stack) */
53271
53272 /* First enumerated key index in enumerator object, must match exactly the
53273  * number of control properties inserted to the enumerator.
53274  */
53275 #define DUK__ENUM_START_INDEX  2
53276
53277 /* Current implementation suffices for ES2015 for now because there's no symbol
53278  * sorting, so commented out for now.
53279  */
53280
53281 /*
53282  *  Helper to sort enumeration keys using a callback for pairwise duk_hstring
53283  *  comparisons.  The keys are in the enumeration object entry part, starting
53284  *  from DUK__ENUM_START_INDEX, and the entry part is dense.  Entry part values
53285  *  are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true, "2" -> true,
53286  *  so it suffices to just switch keys without switching values.
53287  *
53288  *  ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects:
53289  *  (1) array indices in ascending order,
53290  *  (2) non-array-index keys in insertion order, and
53291  *  (3) symbols in insertion order.
53292  *  http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys.
53293  *
53294  *  This rule is applied to "own properties" at each inheritance level;
53295  *  non-duplicate parent keys always follow child keys.  For example,
53296  *  an inherited array index will enumerate -after- a symbol in the
53297  *  child.
53298  *
53299  *  Insertion sort is used because (1) it's simple and compact, (2) works
53300  *  in-place, (3) minimizes operations if data is already nearly sorted,
53301  *  (4) doesn't reorder elements considered equal.
53302  *  http://en.wikipedia.org/wiki/Insertion_sort
53303  */
53304
53305 /* Sort key, must hold array indices, "not array index" marker, and one more
53306  * higher value for symbols.
53307  */
53308 #if !defined(DUK_USE_SYMBOL_BUILTIN)
53309 typedef duk_uint32_t duk__sort_key_t;
53310 #elif defined(DUK_USE_64BIT_OPS)
53311 typedef duk_uint64_t duk__sort_key_t;
53312 #else
53313 typedef duk_double_t duk__sort_key_t;
53314 #endif
53315
53316 /* Get sort key for a duk_hstring. */
53317 DUK_LOCAL duk__sort_key_t duk__hstring_sort_key(duk_hstring *x) {
53318         duk__sort_key_t val;
53319
53320         /* For array indices [0,0xfffffffe] use the array index as is.
53321          * For strings, use 0xffffffff, the marker 'arridx' already in
53322          * duk_hstring.  For symbols, any value above 0xffffffff works,
53323          * as long as it is the same for all symbols; currently just add
53324          * the masked flag field into the arridx temporary.
53325          */
53326         DUK_ASSERT(x != NULL);
53327         DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(x) || DUK_HSTRING_GET_ARRIDX_FAST(x) == DUK_HSTRING_NO_ARRAY_INDEX);
53328
53329         val = (duk__sort_key_t) DUK_HSTRING_GET_ARRIDX_FAST(x);
53330
53331 #if defined(DUK_USE_SYMBOL_BUILTIN)
53332         val = val + (duk__sort_key_t) (DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) x) & DUK_HSTRING_FLAG_SYMBOL);
53333 #endif
53334
53335         return (duk__sort_key_t) val;
53336 }
53337
53338 /* Insert element 'b' after element 'a'? */
53339 DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk__sort_key_t val_b) {
53340         duk__sort_key_t val_a;
53341
53342         DUK_ASSERT(a != NULL);
53343         DUK_ASSERT(b != NULL);
53344         DUK_UNREF(b);  /* Not actually needed now, val_b suffices. */
53345
53346         val_a = duk__hstring_sort_key(a);
53347
53348         if (val_a > val_b) {
53349                 return 0;
53350         } else {
53351                 return 1;
53352         }
53353 }
53354
53355 DUK_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) {
53356         duk_hstring **keys;
53357         duk_int_fast32_t idx;
53358
53359         DUK_ASSERT(h_obj != NULL);
53360         DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX);
53361         DUK_ASSERT(idx_end >= idx_start);
53362         DUK_UNREF(thr);
53363
53364         if (idx_end <= idx_start + 1) {
53365                 return;  /* Zero or one element(s). */
53366         }
53367
53368         keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
53369
53370         for (idx = idx_start + 1; idx < idx_end; idx++) {
53371                 duk_hstring *h_curr;
53372                 duk_int_fast32_t idx_insert;
53373                 duk__sort_key_t val_curr;
53374
53375                 h_curr = keys[idx];
53376                 DUK_ASSERT(h_curr != NULL);
53377
53378                 /* Scan backwards for insertion place.  This works very well
53379                  * when the elements are nearly in order which is the common
53380                  * (and optimized for) case.
53381                  */
53382
53383                 val_curr = duk__hstring_sort_key(h_curr);  /* Remains same during scanning. */
53384                 for (idx_insert = idx - 1; idx_insert >= idx_start; idx_insert--) {
53385                         duk_hstring *h_insert;
53386                         h_insert = keys[idx_insert];
53387                         DUK_ASSERT(h_insert != NULL);
53388
53389                         if (duk__sort_compare_es6(h_insert, h_curr, val_curr)) {
53390                                 break;
53391                         }
53392                 }
53393                 /* If we're out of indices, idx_insert == idx_start - 1 and idx_insert++
53394                  * brings us back to idx_start.
53395                  */
53396                 idx_insert++;
53397                 DUK_ASSERT(idx_insert >= 0 && idx_insert <= idx);
53398
53399                 /*        .-- p_insert   .-- p_curr
53400                  *        v              v
53401                  *  | ... | insert | ... | curr
53402                  */
53403
53404                 /* This could also done when the keys are in order, i.e.
53405                  * idx_insert == idx.  The result would be an unnecessary
53406                  * memmove() but we use an explicit check because the keys
53407                  * are very often in order already.
53408                  */
53409                 if (idx != idx_insert) {
53410                         duk_memmove((void *) (keys + idx_insert + 1),
53411                                     (const void *) (keys + idx_insert),
53412                                     ((size_t) (idx - idx_insert) * sizeof(duk_hstring *)));
53413                         keys[idx_insert] = h_curr;
53414                 }
53415         }
53416 }
53417
53418 /*
53419  *  Create an internal enumerator object E, which has its keys ordered
53420  *  to match desired enumeration ordering.  Also initialize internal control
53421  *  properties for enumeration.
53422  *
53423  *  Note: if an array was used to hold enumeration keys instead, an array
53424  *  scan would be needed to eliminate duplicates found in the prototype chain.
53425  */
53426
53427 DUK_LOCAL void duk__add_enum_key(duk_hthread *thr, duk_hstring *k) {
53428         /* 'k' may be unreachable on entry so must push without any
53429          * potential for GC.
53430          */
53431         duk_push_hstring(thr, k);
53432         duk_push_true(thr);
53433         duk_put_prop(thr, -3);
53434 }
53435
53436 DUK_LOCAL void duk__add_enum_key_stridx(duk_hthread *thr, duk_small_uint_t stridx) {
53437         duk__add_enum_key(thr, DUK_HTHREAD_GET_STRING(thr, stridx));
53438 }
53439
53440 DUK_INTERNAL void duk_hobject_enumerator_create(duk_hthread *thr, duk_small_uint_t enum_flags) {
53441         duk_hobject *enum_target;
53442         duk_hobject *curr;
53443         duk_hobject *res;
53444 #if defined(DUK_USE_ES6_PROXY)
53445         duk_hobject *h_proxy_target;
53446         duk_hobject *h_proxy_handler;
53447         duk_hobject *h_trap_result;
53448 #endif
53449         duk_uint_fast32_t i, len;  /* used for array, stack, and entry indices */
53450         duk_uint_fast32_t sort_start_index;
53451
53452         DUK_ASSERT(thr != NULL);
53453
53454         enum_target = duk_require_hobject(thr, -1);
53455         DUK_ASSERT(enum_target != NULL);
53456
53457         duk_push_bare_object(thr);
53458         res = duk_known_hobject(thr, -1);
53459
53460         /* [enum_target res] */
53461
53462         /* Target must be stored so that we can recheck whether or not
53463          * keys still exist when we enumerate.  This is not done if the
53464          * enumeration result comes from a proxy trap as there is no
53465          * real object to check against.
53466          */
53467         duk_push_hobject(thr, enum_target);
53468         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_TARGET);
53469
53470         /* Initialize index so that we skip internal control keys. */
53471         duk_push_int(thr, DUK__ENUM_START_INDEX);
53472         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT);
53473
53474         /*
53475          *  Proxy object handling
53476          */
53477
53478 #if defined(DUK_USE_ES6_PROXY)
53479         if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
53480                 goto skip_proxy;
53481         }
53482         if (DUK_LIKELY(!duk_hobject_proxy_check(enum_target,
53483                                                 &h_proxy_target,
53484                                                 &h_proxy_handler))) {
53485                 goto skip_proxy;
53486         }
53487
53488         /* XXX: share code with Object.keys() Proxy handling */
53489
53490         /* In ES2015 for-in invoked the "enumerate" trap; in ES2016 "enumerate"
53491          * has been obsoleted and "ownKeys" is used instead.
53492          */
53493         DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
53494         duk_push_hobject(thr, h_proxy_handler);
53495         if (!duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_OWN_KEYS)) {
53496                 /* No need to replace the 'enum_target' value in stack, only the
53497                  * enum_target reference.  This also ensures that the original
53498                  * enum target is reachable, which keeps the proxy and the proxy
53499                  * target reachable.  We do need to replace the internal _Target.
53500                  */
53501                 DUK_DDD(DUK_DDDPRINT("no ownKeys trap, enumerate proxy target instead"));
53502                 DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
53503                 enum_target = h_proxy_target;
53504
53505                 duk_push_hobject(thr, enum_target);  /* -> [ ... enum_target res handler undefined target ] */
53506                 duk_put_prop_stridx_short(thr, -4, DUK_STRIDX_INT_TARGET);
53507
53508                 duk_pop_2(thr);  /* -> [ ... enum_target res ] */
53509                 goto skip_proxy;
53510         }
53511
53512         /* [ ... enum_target res handler trap ] */
53513         duk_insert(thr, -2);
53514         duk_push_hobject(thr, h_proxy_target);    /* -> [ ... enum_target res trap handler target ] */
53515         duk_call_method(thr, 1 /*nargs*/);        /* -> [ ... enum_target res trap_result ] */
53516         h_trap_result = duk_require_hobject(thr, -1);
53517         DUK_UNREF(h_trap_result);
53518
53519         duk_proxy_ownkeys_postprocess(thr, h_proxy_target, enum_flags);
53520         /* -> [ ... enum_target res trap_result keys_array ] */
53521
53522         /* Copy cleaned up trap result keys into the enumerator object. */
53523         /* XXX: result is a dense array; could make use of that. */
53524         DUK_ASSERT(duk_is_array(thr, -1));
53525         len = (duk_uint_fast32_t) duk_get_length(thr, -1);
53526         for (i = 0; i < len; i++) {
53527                 (void) duk_get_prop_index(thr, -1, (duk_uarridx_t) i);
53528                 DUK_ASSERT(duk_is_string(thr, -1));  /* postprocess cleaned up */
53529                 /* [ ... enum_target res trap_result keys_array val ] */
53530                 duk_push_true(thr);
53531                 /* [ ... enum_target res trap_result keys_array val true ] */
53532                 duk_put_prop(thr, -5);
53533         }
53534         /* [ ... enum_target res trap_result keys_array ] */
53535         duk_pop_2(thr);
53536         duk_remove_m2(thr);
53537
53538         /* [ ... res ] */
53539
53540         /* The internal _Target property is kept pointing to the original
53541          * enumeration target (the proxy object), so that the enumerator
53542          * 'next' operation can read property values if so requested.  The
53543          * fact that the _Target is a proxy disables key existence check
53544          * during enumeration.
53545          */
53546         DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O", (duk_heaphdr *) res));
53547         goto compact_and_return;
53548
53549  skip_proxy:
53550 #endif  /* DUK_USE_ES6_PROXY */
53551
53552         curr = enum_target;
53553         sort_start_index = DUK__ENUM_START_INDEX;
53554         DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(res) == DUK__ENUM_START_INDEX);
53555         while (curr) {
53556                 duk_uint_fast32_t sort_end_index;
53557 #if !defined(DUK_USE_PREFER_SIZE)
53558                 duk_bool_t need_sort = 0;
53559 #endif
53560
53561                 /* Enumeration proceeds by inheritance level.  Virtual
53562                  * properties need to be handled specially, followed by
53563                  * array part, and finally entry part.
53564                  *
53565                  * If there are array index keys in the entry part or any
53566                  * other risk of the ES2015 [[OwnPropertyKeys]] order being
53567                  * violated, need_sort is set and an explicit ES2015 sort is
53568                  * done for the inheritance level.
53569                  */
53570
53571                 /* XXX: inheriting from proxy */
53572
53573                 /*
53574                  *  Virtual properties.
53575                  *
53576                  *  String and buffer indices are virtual and always enumerable,
53577                  *  'length' is virtual and non-enumerable.  Array and arguments
53578                  *  object props have special behavior but are concrete.
53579                  *
53580                  *  String and buffer objects don't have an array part so as long
53581                  *  as virtual array index keys are enumerated first, we don't
53582                  *  need to set need_sort.
53583                  */
53584
53585 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
53586                 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) || DUK_HOBJECT_IS_BUFOBJ(curr)) {
53587 #else
53588                 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
53589 #endif
53590                         duk_bool_t have_length = 1;
53591
53592                         /* String and buffer enumeration behavior is identical now,
53593                          * so use shared handler.
53594                          */
53595                         if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
53596                                 duk_hstring *h_val;
53597                                 h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
53598                                 DUK_ASSERT(h_val != NULL);  /* string objects must not created without internal value */
53599                                 len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val);
53600                         }
53601 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
53602                         else {
53603                                 duk_hbufobj *h_bufobj;
53604                                 DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(curr));
53605                                 h_bufobj = (duk_hbufobj *) curr;
53606
53607                                 if (h_bufobj == NULL || !h_bufobj->is_typedarray) {
53608                                         /* Zero length seems like a good behavior for neutered buffers.
53609                                          * ArrayBuffer (non-view) and DataView don't have index properties
53610                                          * or .length property.
53611                                          */
53612                                         len = 0;
53613                                         have_length = 0;
53614                                 } else {
53615                                         /* There's intentionally no check for
53616                                          * current underlying buffer length.
53617                                          */
53618                                         len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift);
53619                                 }
53620                         }
53621 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
53622
53623                         for (i = 0; i < len; i++) {
53624                                 duk_hstring *k;
53625
53626                                 /* This is a bit fragile: the string is not
53627                                  * reachable until it is pushed by the helper.
53628                                  */
53629                                 k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i);
53630                                 DUK_ASSERT(k);
53631
53632                                 duk__add_enum_key(thr, k);
53633
53634                                 /* [enum_target res] */
53635                         }
53636
53637                         /* 'length' and other virtual properties are not
53638                          * enumerable, but are included if non-enumerable
53639                          * properties are requested.
53640                          */
53641
53642                         if (have_length && (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
53643                                 duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
53644                         }
53645                 }
53646
53647                 /*
53648                  *  Array part
53649                  */
53650
53651                 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) {
53652                         duk_hstring *k;
53653                         duk_tval *tv;
53654
53655                         tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i);
53656                         if (DUK_TVAL_IS_UNUSED(tv)) {
53657                                 continue;
53658                         }
53659                         k = duk_heap_strtable_intern_u32_checked(thr, (duk_uint32_t) i);  /* Fragile reachability. */
53660                         DUK_ASSERT(k);
53661
53662                         duk__add_enum_key(thr, k);
53663
53664                         /* [enum_target res] */
53665                 }
53666
53667                 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(curr)) {
53668                         /* Array .length comes after numeric indices. */
53669                         if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
53670                                 duk__add_enum_key_stridx(thr, DUK_STRIDX_LENGTH);
53671                         }
53672                 }
53673
53674                 /*
53675                  *  Entries part
53676                  */
53677
53678                 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) {
53679                         duk_hstring *k;
53680
53681                         k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i);
53682                         if (!k) {
53683                                 continue;
53684                         }
53685                         if (!(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) &&
53686                             !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) {
53687                                 continue;
53688                         }
53689                         if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(k))) {
53690                                 if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) &&
53691                                     DUK_HSTRING_HAS_HIDDEN(k)) {
53692                                         continue;
53693                                 }
53694                                 if (!(enum_flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
53695                                         continue;
53696                                 }
53697 #if !defined(DUK_USE_PREFER_SIZE)
53698                                 need_sort = 1;
53699 #endif
53700                         } else {
53701                                 DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(k));  /* would also have symbol flag */
53702                                 if (enum_flags & DUK_ENUM_EXCLUDE_STRINGS) {
53703                                         continue;
53704                                 }
53705                         }
53706                         if (DUK_HSTRING_HAS_ARRIDX(k)) {
53707                                 /* This in currently only possible if the
53708                                  * object has no array part: the array part
53709                                  * is exhaustive when it is present.
53710                                  */
53711 #if !defined(DUK_USE_PREFER_SIZE)
53712                                 need_sort = 1;
53713 #endif
53714                         } else {
53715                                 if (enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) {
53716                                         continue;
53717                                 }
53718                         }
53719
53720                         DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
53721                                    !DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
53722
53723                         duk__add_enum_key(thr, k);
53724
53725                         /* [enum_target res] */
53726                 }
53727
53728                 /* Sort enumerated keys according to ES2015 requirements for
53729                  * the "inheritance level" just processed.  This is far from
53730                  * optimal, ES2015 semantics could be achieved more efficiently
53731                  * by handling array index string keys (and symbol keys)
53732                  * specially above in effect doing the sort inline.
53733                  *
53734                  * Skip the sort if array index sorting is requested because
53735                  * we must consider all keys, also inherited, so an explicit
53736                  * sort is done for the whole result after we're done with the
53737                  * prototype chain.
53738                  *
53739                  * Also skip the sort if need_sort == 0, i.e. we know for
53740                  * certain that the enumerated order is already correct.
53741                  */
53742                 sort_end_index = DUK_HOBJECT_GET_ENEXT(res);
53743
53744                 if (!(enum_flags & DUK_ENUM_SORT_ARRAY_INDICES)) {
53745 #if defined(DUK_USE_PREFER_SIZE)
53746                         duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
53747 #else
53748                         if (need_sort) {
53749                                 DUK_DDD(DUK_DDDPRINT("need to sort"));
53750                                 duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) sort_start_index, (duk_int_fast32_t) sort_end_index);
53751                         } else {
53752                                 DUK_DDD(DUK_DDDPRINT("no need to sort"));
53753                         }
53754 #endif
53755                 }
53756
53757                 sort_start_index = sort_end_index;
53758
53759                 if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
53760                         break;
53761                 }
53762
53763                 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
53764         }
53765
53766         /* [enum_target res] */
53767
53768         duk_remove_m2(thr);
53769
53770         /* [res] */
53771
53772         if (enum_flags & DUK_ENUM_SORT_ARRAY_INDICES) {
53773                 /* Some E5/E5.1 algorithms require that array indices are iterated
53774                  * in a strictly ascending order.  This is the case for e.g.
53775                  * Array.prototype.forEach() and JSON.stringify() PropertyList
53776                  * handling.  The caller can request an explicit sort in these
53777                  * cases.
53778                  */
53779
53780                 /* Sort to ES2015 order which works for pure array incides but
53781                  * also for mixed keys.
53782                  */
53783                 duk__sort_enum_keys_es6(thr, res, (duk_int_fast32_t) DUK__ENUM_START_INDEX, (duk_int_fast32_t) DUK_HOBJECT_GET_ENEXT(res));
53784         }
53785
53786 #if defined(DUK_USE_ES6_PROXY)
53787  compact_and_return:
53788 #endif
53789         /* compact; no need to seal because object is internal */
53790         duk_hobject_compact_props(thr, res);
53791
53792         DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(thr, -1)));
53793 }
53794
53795 /*
53796  *  Returns non-zero if a key and/or value was enumerated, and:
53797  *
53798  *   [enum] -> [key]        (get_value == 0)
53799  *   [enum] -> [key value]  (get_value == 1)
53800  *
53801  *  Returns zero without pushing anything on the stack otherwise.
53802  */
53803 DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_hthread *thr, duk_bool_t get_value) {
53804         duk_hobject *e;
53805         duk_hobject *enum_target;
53806         duk_hstring *res = NULL;
53807         duk_uint_fast32_t idx;
53808         duk_bool_t check_existence;
53809
53810         DUK_ASSERT(thr != NULL);
53811
53812         /* [... enum] */
53813
53814         e = duk_require_hobject(thr, -1);
53815
53816         /* XXX use get tval ptr, more efficient */
53817         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_NEXT);
53818         idx = (duk_uint_fast32_t) duk_require_uint(thr, -1);
53819         duk_pop(thr);
53820         DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
53821
53822         /* Enumeration keys are checked against the enumeration target (to see
53823          * that they still exist).  In the proxy enumeration case _Target will
53824          * be the proxy, and checking key existence against the proxy is not
53825          * required (or sensible, as the keys may be fully virtual).
53826          */
53827         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_TARGET);
53828         enum_target = duk_require_hobject(thr, -1);
53829         DUK_ASSERT(enum_target != NULL);
53830 #if defined(DUK_USE_ES6_PROXY)
53831         check_existence = (!DUK_HOBJECT_IS_PROXY(enum_target));
53832 #else
53833         check_existence = 1;
53834 #endif
53835         duk_pop(thr);  /* still reachable */
53836
53837         DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
53838                              (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(thr, -1)));
53839
53840         /* no array part */
53841         for (;;) {
53842                 duk_hstring *k;
53843
53844                 if (idx >= DUK_HOBJECT_GET_ENEXT(e)) {
53845                         DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements"));
53846                         break;
53847                 }
53848
53849                 /* we know these because enum objects are internally created */
53850                 k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx);
53851                 DUK_ASSERT(k != NULL);
53852                 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx));
53853                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v));
53854
53855                 idx++;
53856
53857                 /* recheck that the property still exists */
53858                 if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) {
53859                         DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip"));
53860                         continue;
53861                 }
53862
53863                 DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O", (duk_heaphdr *) k));
53864                 res = k;
53865                 break;
53866         }
53867
53868         DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
53869
53870         duk_push_u32(thr, (duk_uint32_t) idx);
53871         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_INT_NEXT);
53872
53873         /* [... enum] */
53874
53875         if (res) {
53876                 duk_push_hstring(thr, res);
53877                 if (get_value) {
53878                         duk_push_hobject(thr, enum_target);
53879                         duk_dup_m2(thr);       /* -> [... enum key enum_target key] */
53880                         duk_get_prop(thr, -2); /* -> [... enum key enum_target val] */
53881                         duk_remove_m2(thr);    /* -> [... enum key val] */
53882                         duk_remove(thr, -3);   /* -> [... key val] */
53883                 } else {
53884                         duk_remove_m2(thr);    /* -> [... key] */
53885                 }
53886                 return 1;
53887         } else {
53888                 duk_pop(thr);  /* -> [...] */
53889                 return 0;
53890         }
53891 }
53892
53893 /*
53894  *  Get enumerated keys in an ECMAScript array.  Matches Object.keys() behavior
53895  *  described in E5 Section 15.2.3.14.
53896  */
53897
53898 DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_hthread *thr, duk_small_uint_t enum_flags) {
53899         duk_hobject *e;
53900         duk_hstring **keys;
53901         duk_tval *tv;
53902         duk_uint_fast32_t count;
53903
53904         DUK_ASSERT(thr != NULL);
53905         DUK_ASSERT(duk_get_hobject(thr, -1) != NULL);
53906
53907         /* Create a temporary enumerator to get the (non-duplicated) key list;
53908          * the enumerator state is initialized without being needed, but that
53909          * has little impact.
53910          */
53911
53912         duk_hobject_enumerator_create(thr, enum_flags);
53913         e = duk_known_hobject(thr, -1);
53914
53915         /* [enum_target enum res] */
53916
53917         /* Create dense result array to exact size. */
53918         DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(e) >= DUK__ENUM_START_INDEX);
53919         count = (duk_uint32_t) (DUK_HOBJECT_GET_ENEXT(e) - DUK__ENUM_START_INDEX);
53920
53921         /* XXX: uninit would be OK */
53922         tv = duk_push_harray_with_size_outptr(thr, (duk_uint32_t) count);
53923         DUK_ASSERT(count == 0 || tv != NULL);
53924
53925         /* Fill result array, no side effects. */
53926
53927         keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, e);
53928         keys += DUK__ENUM_START_INDEX;
53929
53930         while (count-- > 0) {
53931                 duk_hstring *k;
53932
53933                 k = *keys++;
53934                 DUK_ASSERT(k != NULL);  /* enumerator must have no keys deleted */
53935
53936                 DUK_TVAL_SET_STRING(tv, k);
53937                 tv++;
53938                 DUK_HSTRING_INCREF(thr, k);
53939         }
53940
53941         /* [enum_target enum res] */
53942         duk_remove_m2(thr);
53943
53944         /* [enum_target res] */
53945
53946         return 1;  /* return 1 to allow callers to tail call */
53947 }
53948
53949 /* automatic undefs */
53950 #undef DUK__ENUM_START_INDEX
53951 #line 1 "duk_hobject_misc.c"
53952 /*
53953  *  Misc support functions
53954  */
53955
53956 /* #include duk_internal.h -> already included */
53957
53958 DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) {
53959         duk_uint_t sanity;
53960
53961         DUK_ASSERT(thr != NULL);
53962
53963         /* False if the object is NULL or the prototype 'p' is NULL.
53964          * In particular, false if both are NULL (don't compare equal).
53965          */
53966         if (h == NULL || p == NULL) {
53967                 return 0;
53968         }
53969
53970         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
53971         do {
53972                 if (h == p) {
53973                         return 1;
53974                 }
53975
53976                 if (sanity-- == 0) {
53977                         if (ignore_loop) {
53978                                 break;
53979                         } else {
53980                                 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
53981                                 DUK_WO_NORETURN(return 0;);
53982                         }
53983                 }
53984                 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
53985         } while (h);
53986
53987         return 0;
53988 }
53989
53990 DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
53991 #if defined(DUK_USE_REFERENCE_COUNTING)
53992         duk_hobject *tmp;
53993
53994         DUK_ASSERT(h);
53995         tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
53996         DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
53997         DUK_HOBJECT_INCREF_ALLOWNULL(thr, p);  /* avoid problems if p == h->prototype */
53998         DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
53999 #else
54000         DUK_ASSERT(h);
54001         DUK_UNREF(thr);
54002         DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
54003 #endif
54004 }
54005 #line 1 "duk_hobject_pc2line.c"
54006 /*
54007  *  Helpers for creating and querying pc2line debug data, which
54008  *  converts a bytecode program counter to a source line number.
54009  *
54010  *  The run-time pc2line data is bit-packed, and documented in:
54011  *
54012  *    doc/function-objects.rst
54013  */
54014
54015 /* #include duk_internal.h -> already included */
54016
54017 #if defined(DUK_USE_PC2LINE)
54018
54019 /* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
54020 DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
54021         duk_hbuffer_dynamic *h_buf;
54022         duk_bitencoder_ctx be_ctx_alloc;
54023         duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
54024         duk_uint32_t *hdr;
54025         duk_size_t new_size;
54026         duk_uint_fast32_t num_header_entries;
54027         duk_uint_fast32_t curr_offset;
54028         duk_int_fast32_t curr_line, next_line, diff_line;
54029         duk_uint_fast32_t curr_pc;
54030         duk_uint_fast32_t hdr_index;
54031
54032         DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
54033
54034         num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
54035         curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
54036
54037         duk_push_dynamic_buffer(thr, (duk_size_t) curr_offset);
54038         h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
54039         DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
54040
54041         hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
54042         DUK_ASSERT(hdr != NULL);
54043         hdr[0] = (duk_uint32_t) length;  /* valid pc range is [0, length[ */
54044
54045         curr_pc = 0U;
54046         while (curr_pc < length) {
54047                 new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH);
54048                 duk_hbuffer_resize(thr, h_buf, new_size);
54049
54050                 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
54051                 DUK_ASSERT(hdr != NULL);
54052                 DUK_ASSERT(curr_pc < length);
54053                 hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2;
54054                 curr_line = (duk_int_fast32_t) instrs[curr_pc].line;
54055                 hdr[hdr_index + 0] = (duk_uint32_t) curr_line;
54056                 hdr[hdr_index + 1] = (duk_uint32_t) curr_offset;
54057
54058 #if 0
54059                 DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld",
54060                                      (long) (curr_pc / DUK_PC2LINE_SKIP),
54061                                      (long) curr_pc,
54062                                      (long) hdr[hdr_index + 0],
54063                                      (long) hdr[hdr_index + 1]));
54064 #endif
54065
54066                 duk_memzero(be_ctx, sizeof(*be_ctx));
54067                 be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
54068                 be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
54069
54070                 for (;;) {
54071                         curr_pc++;
54072                         if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) ||  /* end of diff run */
54073                              (curr_pc >= length) ) {                 /* end of bytecode */
54074                                 break;
54075                         }
54076                         DUK_ASSERT(curr_pc < length);
54077                         next_line = (duk_int32_t) instrs[curr_pc].line;
54078                         diff_line = next_line - curr_line;
54079
54080 #if 0
54081                         DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld",
54082                                              (long) curr_line, (long) next_line, (long) diff_line));
54083 #endif
54084
54085                         if (diff_line == 0) {
54086                                 /* 0 */
54087                                 duk_be_encode(be_ctx, 0, 1);
54088                         } else if (diff_line >= 1 && diff_line <= 4) {
54089                                 /* 1 0 <2 bits> */
54090                                 duk_be_encode(be_ctx, (duk_uint32_t) ((0x02 << 2) + (diff_line - 1)), 4);
54091                         } else if (diff_line >= -0x80 && diff_line <= 0x7f) {
54092                                 /* 1 1 0 <8 bits> */
54093                                 DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
54094                                 duk_be_encode(be_ctx, (duk_uint32_t) ((0x06 << 8) + (diff_line + 0x80)), 11);
54095                         } else {
54096                                 /* 1 1 1 <32 bits>
54097                                  * Encode in two parts to avoid bitencode 24-bit limitation
54098                                  */
54099                                 duk_be_encode(be_ctx, (duk_uint32_t) ((0x07 << 16) + ((next_line >> 16) & 0xffff)), 19);
54100                                 duk_be_encode(be_ctx, (duk_uint32_t) (next_line & 0xffff), 16);
54101                         }
54102
54103                         curr_line = next_line;
54104                 }
54105
54106                 duk_be_finish(be_ctx);
54107                 DUK_ASSERT(!be_ctx->truncated);
54108
54109                 /* be_ctx->offset == length of encoded bitstream */
54110                 curr_offset += (duk_uint_fast32_t) be_ctx->offset;
54111         }
54112
54113         /* compact */
54114         new_size = (duk_size_t) curr_offset;
54115         duk_hbuffer_resize(thr, h_buf, new_size);
54116
54117         (void) duk_to_fixed_buffer(thr, -1, NULL);
54118
54119         DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
54120                              (long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
54121                              (duk_tval *) duk_get_tval(thr, -1)));
54122 }
54123
54124 /* PC is unsigned.  If caller does PC arithmetic and gets a negative result,
54125  * it will map to a large PC which is out of bounds and causes a zero to be
54126  * returned.
54127  */
54128 DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) {
54129         duk_bitdecoder_ctx bd_ctx_alloc;
54130         duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc;
54131         duk_uint32_t *hdr;
54132         duk_uint_fast32_t start_offset;
54133         duk_uint_fast32_t pc_limit;
54134         duk_uint_fast32_t hdr_index;
54135         duk_uint_fast32_t pc_base;
54136         duk_uint_fast32_t n;
54137         duk_uint_fast32_t curr_line;
54138
54139         DUK_ASSERT(buf != NULL);
54140         DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf));
54141         DUK_UNREF(thr);
54142
54143         /*
54144          *  Use the index in the header to find the right starting point
54145          */
54146
54147         hdr_index = pc / DUK_PC2LINE_SKIP;
54148         pc_base = hdr_index * DUK_PC2LINE_SKIP;
54149         n = pc - pc_base;
54150
54151         if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
54152                 DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header"));
54153                 goto pc2line_error;
54154         }
54155
54156         hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf);
54157         pc_limit = hdr[0];
54158         if (pc >= pc_limit) {
54159                 /* Note: pc is unsigned and cannot be negative */
54160                 DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)",
54161                                    (long) pc, (long) pc_limit));
54162                 goto pc2line_error;
54163         }
54164
54165         curr_line = hdr[1 + hdr_index * 2];
54166         start_offset = hdr[1 + hdr_index * 2 + 1];
54167         if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
54168                 DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)",
54169                                    (long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf)));
54170                 goto pc2line_error;
54171         }
54172
54173         /*
54174          *  Iterate the bitstream (line diffs) until PC is reached
54175          */
54176
54177         duk_memzero(bd_ctx, sizeof(*bd_ctx));
54178         bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
54179         bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
54180
54181 #if 0
54182         DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld",
54183                              (long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset));
54184 #endif
54185
54186         while (n > 0) {
54187 #if 0
54188                 DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld", (long) n, (long) curr_line));
54189 #endif
54190
54191                 if (duk_bd_decode_flag(bd_ctx)) {
54192                         if (duk_bd_decode_flag(bd_ctx)) {
54193                                 if (duk_bd_decode_flag(bd_ctx)) {
54194                                         /* 1 1 1 <32 bits> */
54195                                         duk_uint_fast32_t t;
54196                                         t = duk_bd_decode(bd_ctx, 16);  /* workaround: max nbits = 24 now */
54197                                         t = (t << 16) + duk_bd_decode(bd_ctx, 16);
54198                                         curr_line = t;
54199                                 } else {
54200                                         /* 1 1 0 <8 bits> */
54201                                         duk_uint_fast32_t t;
54202                                         t = duk_bd_decode(bd_ctx, 8);
54203                                         curr_line = curr_line + t - 0x80;
54204                                 }
54205                         } else {
54206                                 /* 1 0 <2 bits> */
54207                                 duk_uint_fast32_t t;
54208                                 t = duk_bd_decode(bd_ctx, 2);
54209                                 curr_line = curr_line + t + 1;
54210                         }
54211                 } else {
54212                         /* 0: no change */
54213                 }
54214
54215                 n--;
54216         }
54217
54218         DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line));
54219         return curr_line;
54220
54221  pc2line_error:
54222         DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc));
54223         return 0;
54224 }
54225
54226 DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_hthread *thr, duk_idx_t idx_func, duk_uint_fast32_t pc) {
54227         duk_hbuffer_fixed *pc2line;
54228         duk_uint_fast32_t line;
54229
54230         /* XXX: now that pc2line is used by the debugger quite heavily in
54231          * checked execution, this should be optimized to avoid value stack
54232          * and perhaps also implement some form of pc2line caching (see
54233          * future work in debugger.rst).
54234          */
54235
54236         duk_get_prop_stridx(thr, idx_func, DUK_STRIDX_INT_PC2LINE);
54237         pc2line = (duk_hbuffer_fixed *) (void *) duk_get_hbuffer(thr, -1);
54238         if (pc2line != NULL) {
54239                 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
54240                 line = duk__hobject_pc2line_query_raw(thr, pc2line, (duk_uint_fast32_t) pc);
54241         } else {
54242                 line = 0;
54243         }
54244         duk_pop(thr);
54245
54246         return line;
54247 }
54248
54249 #endif  /* DUK_USE_PC2LINE */
54250 #line 1 "duk_hobject_props.c"
54251 /*
54252  *  duk_hobject property access functionality.
54253  *
54254  *  This is very central functionality for size, performance, and compliance.
54255  *  It is also rather intricate; see hobject-algorithms.rst for discussion on
54256  *  the algorithms and memory-management.rst for discussion on refcounts and
54257  *  side effect issues.
54258  *
54259  *  Notes:
54260  *
54261  *    - It might be tempting to assert "refcount nonzero" for objects
54262  *      being operated on, but that's not always correct: objects with
54263  *      a zero refcount may be operated on by the refcount implementation
54264  *      (finalization) for instance.  Hence, no refcount assertions are made.
54265  *
54266  *    - Many operations (memory allocation, identifier operations, etc)
54267  *      may cause arbitrary side effects (e.g. through GC and finalization).
54268  *      These side effects may invalidate duk_tval pointers which point to
54269  *      areas subject to reallocation (like value stack).  Heap objects
54270  *      themselves have stable pointers.  Holding heap object pointers or
54271  *      duk_tval copies is not problematic with respect to side effects;
54272  *      care must be taken when holding and using argument duk_tval pointers.
54273  *
54274  *    - If a finalizer is executed, it may operate on the the same object
54275  *      we're currently dealing with.  For instance, the finalizer might
54276  *      delete a certain property which has already been looked up and
54277  *      confirmed to exist.  Ideally finalizers would be disabled if GC
54278  *      happens during property access.  At the moment property table realloc
54279  *      disables finalizers, and all DECREFs may cause arbitrary changes so
54280  *      handle DECREF carefully.
54281  *
54282  *    - The order of operations for a DECREF matters.  When DECREF is executed,
54283  *      the entire object graph must be consistent; note that a refzero may
54284  *      lead to a mark-and-sweep through a refcount finalizer.  Use NORZ macros
54285  *      and an explicit DUK_REFZERO_CHECK_xxx() if achieving correct order is hard.
54286  */
54287
54288 /*
54289  *  XXX: array indices are mostly typed as duk_uint32_t here; duk_uarridx_t
54290  *  might be more appropriate.
54291  */
54292
54293 /* #include duk_internal.h -> already included */
54294
54295 /*
54296  *  Local defines
54297  */
54298
54299 #define DUK__NO_ARRAY_INDEX             DUK_HSTRING_NO_ARRAY_INDEX
54300
54301 /* Marker values for hash part. */
54302 #define DUK__HASH_UNUSED                DUK_HOBJECT_HASHIDX_UNUSED
54303 #define DUK__HASH_DELETED               DUK_HOBJECT_HASHIDX_DELETED
54304
54305 /* Valstack space that suffices for all local calls, excluding any recursion
54306  * into ECMAScript or Duktape/C calls (Proxy, getters, etc).
54307  */
54308 #define DUK__VALSTACK_SPACE             10
54309
54310 /* Valstack space allocated especially for proxy lookup which does a
54311  * recursive property lookup.
54312  */
54313 #define DUK__VALSTACK_PROXY_LOOKUP      20
54314
54315 /*
54316  *  Local prototypes
54317  */
54318
54319 DUK_LOCAL_DECL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
54320 DUK_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);
54321 DUK_LOCAL_DECL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
54322
54323 DUK_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);
54324 DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj);
54325
54326 DUK_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);
54327 DUK_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);
54328
54329 /*
54330  *  Misc helpers
54331  */
54332
54333 /* Convert a duk_tval number (caller checks) to a 32-bit index.  Returns
54334  * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array
54335  * index.
54336  */
54337 /* XXX: for fastints, could use a variant which assumes a double duk_tval
54338  * (and doesn't need to check for fastint again).
54339  */
54340 DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) {
54341         duk_double_t dbl;
54342         duk_uint32_t idx;
54343
54344         DUK_ASSERT(tv != NULL);
54345         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
54346
54347         /* -0 is accepted here as index 0 because ToString(-0) == "0" which is
54348          * in canonical form and thus an array index.
54349          */
54350         dbl = DUK_TVAL_GET_NUMBER(tv);
54351         idx = (duk_uint32_t) dbl;
54352         if ((duk_double_t) idx == dbl) {
54353                 /* Is whole and within 32 bit range.  If the value happens to be 0xFFFFFFFF,
54354                  * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX.
54355                  */
54356                 return idx;
54357         }
54358         return DUK__NO_ARRAY_INDEX;
54359 }
54360
54361 #if defined(DUK_USE_FASTINT)
54362 /* Convert a duk_tval fastint (caller checks) to a 32-bit index. */
54363 DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
54364         duk_int64_t t;
54365
54366         DUK_ASSERT(tv != NULL);
54367         DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
54368
54369         t = DUK_TVAL_GET_FASTINT(tv);
54370         if (((duk_uint64_t) t & ~DUK_U64_CONSTANT(0xffffffff)) != 0) {
54371                 /* Catches >0x100000000 and negative values. */
54372                 return DUK__NO_ARRAY_INDEX;
54373         }
54374
54375         /* If the value happens to be 0xFFFFFFFF, it's not a valid array index
54376          * but will then match DUK__NO_ARRAY_INDEX.
54377          */
54378         return (duk_uint32_t) t;
54379 }
54380 #endif  /* DUK_USE_FASTINT */
54381
54382 /* Convert a duk_tval on the value stack (in a trusted index we don't validate)
54383  * to a string or symbol using ES2015 ToPropertyKey():
54384  * http://www.ecma-international.org/ecma-262/6.0/#sec-topropertykey.
54385  *
54386  * Also check if it's a valid array index and return that (or DUK__NO_ARRAY_INDEX
54387  * if not).
54388  */
54389 DUK_LOCAL duk_uint32_t duk__to_property_key(duk_hthread *thr, duk_idx_t idx, duk_hstring **out_h) {
54390         duk_uint32_t arr_idx;
54391         duk_hstring *h;
54392         duk_tval *tv_dst;
54393
54394         DUK_ASSERT(thr != NULL);
54395         DUK_ASSERT(out_h != NULL);
54396         DUK_ASSERT(duk_is_valid_index(thr, idx));
54397         DUK_ASSERT(idx < 0);
54398
54399         /* XXX: The revised ES2015 ToPropertyKey() handling (ES5.1 was just
54400          * ToString()) involves a ToPrimitive(), a symbol check, and finally
54401          * a ToString().  Figure out the best way to have a good fast path
54402          * but still be compliant and share code.
54403          */
54404
54405         tv_dst = DUK_GET_TVAL_NEGIDX(thr, idx);  /* intentionally unvalidated */
54406         if (DUK_TVAL_IS_STRING(tv_dst)) {
54407                 /* Most important path: strings and plain symbols are used as
54408                  * is.  For symbols the array index check below is unnecessary
54409                  * (they're never valid array indices) but checking that the
54410                  * string is a symbol would make the plain string path slower
54411                  * unnecessarily.
54412                  */
54413                 h = DUK_TVAL_GET_STRING(tv_dst);
54414         } else {
54415                 h = duk_to_property_key_hstring(thr, idx);
54416         }
54417         DUK_ASSERT(h != NULL);
54418         *out_h = h;
54419
54420         arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h);
54421         return arr_idx;
54422 }
54423
54424 DUK_LOCAL duk_uint32_t duk__push_tval_to_property_key(duk_hthread *thr, duk_tval *tv_key, duk_hstring **out_h) {
54425         duk_push_tval(thr, tv_key);  /* XXX: could use an unsafe push here */
54426         return duk__to_property_key(thr, -1, out_h);
54427 }
54428
54429 /* String is an own (virtual) property of a plain buffer. */
54430 DUK_LOCAL duk_bool_t duk__key_is_plain_buf_ownprop(duk_hthread *thr, duk_hbuffer *buf, duk_hstring *key, duk_uint32_t arr_idx) {
54431         DUK_UNREF(thr);
54432
54433         /* Virtual index properties.  Checking explicitly for
54434          * 'arr_idx != DUK__NO_ARRAY_INDEX' is not necessary
54435          * because DUK__NO_ARRAY_INDEXi is always larger than
54436          * maximum allowed buffer size.
54437          */
54438         DUK_ASSERT(DUK__NO_ARRAY_INDEX >= DUK_HBUFFER_GET_SIZE(buf));
54439         if (arr_idx < DUK_HBUFFER_GET_SIZE(buf)) {
54440                 return 1;
54441         }
54442
54443         /* Other virtual properties. */
54444         return (key == DUK_HTHREAD_STRING_LENGTH(thr));
54445 }
54446
54447 /*
54448  *  Helpers for managing property storage size
54449  */
54450
54451 /* Get default hash part size for a certain entry part size. */
54452 #if defined(DUK_USE_HOBJECT_HASH_PART)
54453 DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) {
54454         DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
54455
54456         if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) {
54457                 duk_uint32_t res;
54458                 duk_uint32_t tmp;
54459
54460                 /* Hash size should be 2^N where N is chosen so that 2^N is
54461                  * larger than e_size.  Extra shifting is used to ensure hash
54462                  * is relatively sparse.
54463                  */
54464                 tmp = e_size;
54465                 res = 2;  /* Result will be 2 ** (N + 1). */
54466                 while (tmp >= 0x40) {
54467                         tmp >>= 6;
54468                         res <<= 6;
54469                 }
54470                 while (tmp != 0) {
54471                         tmp >>= 1;
54472                         res <<= 1;
54473                 }
54474                 DUK_ASSERT((DUK_HOBJECT_MAX_PROPERTIES << 2U) > DUK_HOBJECT_MAX_PROPERTIES);  /* Won't wrap, even shifted by 2. */
54475                 DUK_ASSERT(res > e_size);
54476                 return res;
54477         } else {
54478                 return 0;
54479         }
54480 }
54481 #endif  /* USE_PROP_HASH_PART */
54482
54483 /* Get minimum entry part growth for a certain size. */
54484 DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) {
54485         duk_uint32_t res;
54486
54487         DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
54488
54489         res = (e_size + DUK_USE_HOBJECT_ENTRY_MINGROW_ADD) / DUK_USE_HOBJECT_ENTRY_MINGROW_DIVISOR;
54490         DUK_ASSERT(res >= 1);  /* important for callers */
54491         return res;
54492 }
54493
54494 /* Get minimum array part growth for a certain size. */
54495 DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) {
54496         duk_uint32_t res;
54497
54498         DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES);
54499
54500         res = (a_size + DUK_USE_HOBJECT_ARRAY_MINGROW_ADD) / DUK_USE_HOBJECT_ARRAY_MINGROW_DIVISOR;
54501         DUK_ASSERT(res >= 1);  /* important for callers */
54502         return res;
54503 }
54504
54505 /* Count actually used entry part entries (non-NULL keys). */
54506 DUK_LOCAL duk_uint32_t duk__count_used_e_keys(duk_hthread *thr, duk_hobject *obj) {
54507         duk_uint_fast32_t i;
54508         duk_uint_fast32_t n = 0;
54509         duk_hstring **e;
54510
54511         DUK_ASSERT(obj != NULL);
54512         DUK_UNREF(thr);
54513
54514         e = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, obj);
54515         for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
54516                 if (*e++) {
54517                         n++;
54518                 }
54519         }
54520         return (duk_uint32_t) n;
54521 }
54522
54523 /* Count actually used array part entries and array minimum size.
54524  * NOTE: 'out_min_size' can be computed much faster by starting from the
54525  * end and breaking out early when finding first used entry, but this is
54526  * not needed now.
54527  */
54528 DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) {
54529         duk_uint_fast32_t i;
54530         duk_uint_fast32_t used = 0;
54531         duk_uint_fast32_t highest_idx = (duk_uint_fast32_t) -1;  /* see below */
54532         duk_tval *a;
54533
54534         DUK_ASSERT(obj != NULL);
54535         DUK_ASSERT(out_used != NULL);
54536         DUK_ASSERT(out_min_size != NULL);
54537         DUK_UNREF(thr);
54538
54539         a = DUK_HOBJECT_A_GET_BASE(thr->heap, obj);
54540         for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
54541                 duk_tval *tv = a++;
54542                 if (!DUK_TVAL_IS_UNUSED(tv)) {
54543                         used++;
54544                         highest_idx = i;
54545                 }
54546         }
54547
54548         /* Initial value for highest_idx is -1 coerced to unsigned.  This
54549          * is a bit odd, but (highest_idx + 1) will then wrap to 0 below
54550          * for out_min_size as intended.
54551          */
54552
54553         *out_used = (duk_uint32_t) used;
54554         *out_min_size = (duk_uint32_t) (highest_idx + 1);  /* 0 if no used entries */
54555 }
54556
54557 /* Check array density and indicate whether or not the array part should be abandoned. */
54558 DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) {
54559         /*
54560          *  Array abandon check; abandon if:
54561          *
54562          *    new_used / new_size < limit
54563          *    new_used < limit * new_size        || limit is 3 bits fixed point
54564          *    new_used < limit' / 8 * new_size   || *8
54565          *    8*new_used < limit' * new_size     || :8
54566          *    new_used < limit' * (new_size / 8)
54567          *
54568          *  Here, new_used = a_used, new_size = a_size.
54569          *
54570          *  Note: some callers use approximate values for a_used and/or a_size
54571          *  (e.g. dropping a '+1' term).  This doesn't affect the usefulness
54572          *  of the check, but may confuse debugging.
54573          */
54574
54575         return (a_used < DUK_USE_HOBJECT_ARRAY_ABANDON_LIMIT * (a_size >> 3));
54576 }
54577
54578 /* Fast check for extending array: check whether or not a slow density check is required. */
54579 DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) {
54580         /*
54581          *  In a fast check we assume old_size equals old_used (i.e., existing
54582          *  array is fully dense).
54583          *
54584          *  Slow check if:
54585          *
54586          *    (new_size - old_size) / old_size > limit
54587          *    new_size - old_size > limit * old_size
54588          *    new_size > (1 + limit) * old_size        || limit' is 3 bits fixed point
54589          *    new_size > (1 + (limit' / 8)) * old_size || * 8
54590          *    8 * new_size > (8 + limit') * old_size   || : 8
54591          *    new_size > (8 + limit') * (old_size / 8)
54592          *    new_size > limit'' * (old_size / 8)      || limit'' = 9 -> max 25% increase
54593          *    arr_idx + 1 > limit'' * (old_size / 8)
54594          *
54595          *  This check doesn't work well for small values, so old_size is rounded
54596          *  up for the check (and the '+ 1' of arr_idx can be ignored in practice):
54597          *
54598          *    arr_idx > limit'' * ((old_size + 7) / 8)
54599          */
54600
54601         return (arr_idx > DUK_USE_HOBJECT_ARRAY_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
54602 }
54603
54604 /*
54605  *  Proxy helpers
54606  */
54607
54608 #if defined(DUK_USE_ES6_PROXY)
54609 DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
54610         duk_hproxy *h_proxy;
54611
54612         DUK_ASSERT(obj != NULL);
54613         DUK_ASSERT(out_target != NULL);
54614         DUK_ASSERT(out_handler != NULL);
54615
54616         /* Caller doesn't need to check exotic proxy behavior (but does so for
54617          * some fast paths).
54618          */
54619         if (DUK_LIKELY(!DUK_HOBJECT_IS_PROXY(obj))) {
54620                 return 0;
54621         }
54622         h_proxy = (duk_hproxy *) obj;
54623         DUK_ASSERT_HPROXY_VALID(h_proxy);
54624
54625         DUK_ASSERT(h_proxy->handler != NULL);
54626         DUK_ASSERT(h_proxy->target != NULL);
54627         *out_handler = h_proxy->handler;
54628         *out_target = h_proxy->target;
54629
54630         return 1;
54631 }
54632 #endif  /* DUK_USE_ES6_PROXY */
54633
54634 /* Get Proxy target object.  If the argument is not a Proxy, return it as is.
54635  * If a Proxy is revoked, an error is thrown.
54636  */
54637 #if defined(DUK_USE_ES6_PROXY)
54638 DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hobject *obj) {
54639         DUK_ASSERT(obj != NULL);
54640
54641         /* Resolve Proxy targets until Proxy chain ends.  No explicit check for
54642          * a Proxy loop: user code cannot create such a loop (it would only be
54643          * possible by editing duk_hproxy references directly).
54644          */
54645
54646         while (DUK_HOBJECT_IS_PROXY(obj)) {
54647                 duk_hproxy *h_proxy;
54648
54649                 h_proxy = (duk_hproxy *) obj;
54650                 DUK_ASSERT_HPROXY_VALID(h_proxy);
54651                 obj = h_proxy->target;
54652                 DUK_ASSERT(obj != NULL);
54653         }
54654
54655         DUK_ASSERT(obj != NULL);
54656         return obj;
54657 }
54658 #endif  /* DUK_USE_ES6_PROXY */
54659
54660 #if defined(DUK_USE_ES6_PROXY)
54661 DUK_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) {
54662         duk_hobject *h_handler;
54663
54664         DUK_ASSERT(thr != NULL);
54665         DUK_ASSERT(obj != NULL);
54666         DUK_ASSERT(tv_key != NULL);
54667         DUK_ASSERT(out_target != NULL);
54668
54669         if (!duk_hobject_proxy_check(obj, out_target, &h_handler)) {
54670                 return 0;
54671         }
54672         DUK_ASSERT(*out_target != NULL);
54673         DUK_ASSERT(h_handler != NULL);
54674
54675         /* XXX: At the moment Duktape accesses internal keys like _Finalizer using a
54676          * normal property set/get which would allow a proxy handler to interfere with
54677          * such behavior and to get access to internal key strings.  This is not a problem
54678          * as such because internal key strings can be created in other ways too (e.g.
54679          * through buffers).  The best fix is to change Duktape internal lookups to
54680          * skip proxy behavior.  Until that, internal property accesses bypass the
54681          * proxy and are applied to the target (as if the handler did not exist).
54682          * This has some side effects, see test-bi-proxy-internal-keys.js.
54683          */
54684
54685         if (DUK_TVAL_IS_STRING(tv_key)) {
54686                 duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key);
54687                 DUK_ASSERT(h_key != NULL);
54688                 if (DUK_HSTRING_HAS_HIDDEN(h_key)) {
54689                         /* Symbol accesses must go through proxy lookup in ES2015.
54690                          * Hidden symbols behave like Duktape 1.x internal keys
54691                          * and currently won't.
54692                          */
54693                         DUK_DDD(DUK_DDDPRINT("hidden key, skip proxy handler and apply to target"));
54694                         return 0;
54695                 }
54696         }
54697
54698         /* The handler is looked up with a normal property lookup; it may be an
54699          * accessor or the handler object itself may be a proxy object.  If the
54700          * handler is a proxy, we need to extend the valstack as we make a
54701          * recursive proxy check without a function call in between (in fact
54702          * there is no limit to the potential recursion here).
54703          *
54704          * (For sanity, proxy creation rejects another proxy object as either
54705          * the handler or the target at the moment so recursive proxy cases
54706          * are not realized now.)
54707          */
54708
54709         /* XXX: C recursion limit if proxies are allowed as handler/target values */
54710
54711         duk_require_stack(thr, DUK__VALSTACK_PROXY_LOOKUP);
54712         duk_push_hobject(thr, h_handler);
54713         if (duk_get_prop_stridx_short(thr, -1, stridx_trap)) {
54714                 /* -> [ ... handler trap ] */
54715                 duk_insert(thr, -2);  /* -> [ ... trap handler ] */
54716
54717                 /* stack prepped for func call: [ ... trap handler ] */
54718                 return 1;
54719         } else {
54720                 duk_pop_2_unsafe(thr);
54721                 return 0;
54722         }
54723 }
54724 #endif  /* DUK_USE_ES6_PROXY */
54725
54726 /*
54727  *  Reallocate property allocation, moving properties to the new allocation.
54728  *
54729  *  Includes key compaction, rehashing, and can also optionally abandon
54730  *  the array part, 'migrating' array entries into the beginning of the
54731  *  new entry part.
54732  *
54733  *  There is no support for in-place reallocation or just compacting keys
54734  *  without resizing the property allocation.  This is intentional to keep
54735  *  code size minimal, but would be useful future work.
54736  *
54737  *  The implementation is relatively straightforward, except for the array
54738  *  abandonment process.  Array abandonment requires that new string keys
54739  *  are interned, which may trigger GC.  All keys interned so far must be
54740  *  reachable for GC at all times and correctly refcounted for; valstack is
54741  *  used for that now.
54742  *
54743  *  Also, a GC triggered during this reallocation process must not interfere
54744  *  with the object being resized.  This is currently controlled by preventing
54745  *  finalizers (as they may affect ANY object) and object compaction in
54746  *  mark-and-sweep.  It would suffice to protect only this particular object
54747  *  from compaction, however.  DECREF refzero cascades are side effect free
54748  *  and OK.
54749  *
54750  *  Note: because we need to potentially resize the valstack (as part
54751  *  of abandoning the array part), any tval pointers to the valstack
54752  *  will become invalid after this call.
54753  */
54754
54755 DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
54756                                             duk_hobject *obj,
54757                                             duk_uint32_t new_e_size,
54758                                             duk_uint32_t new_a_size,
54759                                             duk_uint32_t new_h_size,
54760                                             duk_bool_t abandon_array) {
54761         duk_small_uint_t prev_ms_base_flags;
54762         duk_uint32_t new_alloc_size;
54763         duk_uint32_t new_e_size_adjusted;
54764         duk_uint8_t *new_p;
54765         duk_hstring **new_e_k;
54766         duk_propvalue *new_e_pv;
54767         duk_uint8_t *new_e_f;
54768         duk_tval *new_a;
54769         duk_uint32_t *new_h;
54770         duk_uint32_t new_e_next;
54771         duk_uint_fast32_t i;
54772         duk_size_t array_copy_size;
54773 #if defined(DUK_USE_ASSERTIONS)
54774         duk_bool_t prev_error_not_allowed;
54775 #endif
54776
54777         DUK_ASSERT(thr != NULL);
54778         DUK_ASSERT(obj != NULL);
54779         DUK_ASSERT(!abandon_array || new_a_size == 0);  /* if abandon_array, new_a_size must be 0 */
54780         DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0));
54781         DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size);  /* required to guarantee success of rehashing,
54782                                                                    * intentionally use unadjusted new_e_size
54783                                                                    */
54784         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
54785         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
54786
54787         DUK_STATS_INC(thr->heap, stats_object_realloc_props);
54788
54789         /*
54790          *  Pre resize assertions.
54791          */
54792
54793 #if defined(DUK_USE_ASSERTIONS)
54794         /* XXX: pre-checks (such as no duplicate keys) */
54795 #endif
54796
54797         /*
54798          *  For property layout 1, tweak e_size to ensure that the whole entry
54799          *  part (key + val + flags) is a suitable multiple for alignment
54800          *  (platform specific).
54801          *
54802          *  Property layout 2 does not require this tweaking and is preferred
54803          *  on low RAM platforms requiring alignment.
54804          */
54805
54806 #if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3)
54807         DUK_DDD(DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %ld", (long) new_e_size));
54808         new_e_size_adjusted = new_e_size;
54809 #elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1)
54810         DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size));
54811         new_e_size_adjusted = new_e_size;
54812 #elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
54813         new_e_size_adjusted = (new_e_size + (duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U) &
54814                               (~((duk_uint32_t) DUK_HOBJECT_ALIGN_TARGET - 1U));
54815         DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld",
54816                              (long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted));
54817         DUK_ASSERT(new_e_size_adjusted >= new_e_size);
54818 #else
54819 #error invalid hobject layout defines
54820 #endif
54821
54822         /*
54823          *  Debug logging after adjustment.
54824          */
54825
54826         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 "
54827                              "{e_size=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
54828                              (void *) obj,
54829                              (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
54830                                                                DUK_HOBJECT_GET_ASIZE(obj),
54831                                                                DUK_HOBJECT_GET_HSIZE(obj)),
54832                              (long) DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size),
54833                              (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
54834                              (long) DUK_HOBJECT_GET_ESIZE(obj),
54835                              (long) DUK_HOBJECT_GET_ENEXT(obj),
54836                              (long) DUK_HOBJECT_GET_ASIZE(obj),
54837                              (long) DUK_HOBJECT_GET_HSIZE(obj),
54838                              (long) new_e_size_adjusted,
54839                              (long) new_a_size,
54840                              (long) new_h_size,
54841                              (long) abandon_array,
54842                              (long) new_e_size));
54843
54844         /*
54845          *  Property count check.  This is the only point where we ensure that
54846          *  we don't get more (allocated) property space that we can handle.
54847          *  There aren't hard limits as such, but some algorithms may fail
54848          *  if we get too close to the 4G property limit.
54849          *
54850          *  Since this works based on allocation size (not actually used size),
54851          *  the limit is a bit approximate but good enough in practice.
54852          */
54853
54854         if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
54855                 DUK_ERROR_ALLOC_FAILED(thr);
54856                 DUK_WO_NORETURN(return;);
54857         }
54858
54859         /*
54860          *  Compute new alloc size and alloc new area.
54861          *
54862          *  The new area is not tracked in the heap at all, so it's critical
54863          *  we get to free/keep it in a controlled manner.
54864          */
54865
54866 #if defined(DUK_USE_ASSERTIONS)
54867         /* Whole path must be error throw free, but we may be called from
54868          * within error handling so can't assert for error_not_allowed == 0.
54869          */
54870         prev_error_not_allowed = thr->heap->error_not_allowed;
54871         thr->heap->error_not_allowed = 1;
54872 #endif
54873         prev_ms_base_flags = thr->heap->ms_base_flags;
54874         thr->heap->ms_base_flags |=
54875                 DUK_MS_FLAG_NO_OBJECT_COMPACTION;      /* Avoid attempt to compact the current object (all objects really). */
54876         thr->heap->pf_prevent_count++;                 /* Avoid finalizers. */
54877         DUK_ASSERT(thr->heap->pf_prevent_count != 0);  /* Wrap. */
54878
54879         new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size);
54880         DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size));
54881         if (new_alloc_size == 0) {
54882                 DUK_ASSERT(new_e_size_adjusted == 0);
54883                 DUK_ASSERT(new_a_size == 0);
54884                 DUK_ASSERT(new_h_size == 0);
54885                 new_p = NULL;
54886         } else {
54887                 /* Alloc may trigger mark-and-sweep but no compaction, and
54888                  * cannot throw.
54889                  */
54890 #if 0  /* XXX: inject test */
54891                 if (1) {
54892                         new_p = NULL;
54893                         goto alloc_failed;
54894                 }
54895 #endif
54896                 new_p = (duk_uint8_t *) DUK_ALLOC(thr->heap, new_alloc_size);
54897                 if (new_p == NULL) {
54898                         /* NULL always indicates alloc failure because
54899                          * new_alloc_size > 0.
54900                          */
54901                         goto alloc_failed;
54902                 }
54903         }
54904
54905         /* Set up pointers to the new property area: this is hidden behind a macro
54906          * because it is memory layout specific.
54907          */
54908         DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h,
54909                                        new_e_size_adjusted, new_a_size, new_h_size);
54910         DUK_UNREF(new_h);  /* happens when hash part dropped */
54911         new_e_next = 0;
54912
54913         /* if new_p == NULL, all of these pointers are NULL */
54914         DUK_ASSERT((new_p != NULL) ||
54915                    (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL &&
54916                     new_a == NULL && new_h == NULL));
54917
54918         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",
54919                              (long) new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f,
54920                              (void *) new_a, (void *) new_h));
54921
54922         /*
54923          *  Migrate array part to start of entries if requested.
54924          *
54925          *  Note: from an enumeration perspective the order of entry keys matters.
54926          *  Array keys should appear wherever they appeared before the array abandon
54927          *  operation.  (This no longer matters much because keys are ES2015 sorted.)
54928          */
54929
54930         if (abandon_array) {
54931                 /* Assuming new_a_size == 0, and that entry part contains
54932                  * no conflicting keys, refcounts do not need to be adjusted for
54933                  * the values, as they remain exactly the same.
54934                  *
54935                  * The keys, however, need to be interned, incref'd, and be
54936                  * reachable for GC.  Any intern attempt may trigger a GC and
54937                  * claim any non-reachable strings, so every key must be reachable
54938                  * at all times.  Refcounts must be correct to satisfy refcount
54939                  * assertions.
54940                  *
54941                  * A longjmp must not occur here, as the new_p allocation would
54942                  * leak.  Refcounts would come out correctly as the interned
54943                  * strings are valstack tracked.
54944                  */
54945                 DUK_ASSERT(new_a_size == 0);
54946
54947                 DUK_STATS_INC(thr->heap, stats_object_abandon_array);
54948
54949                 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
54950                         duk_tval *tv1;
54951                         duk_tval *tv2;
54952                         duk_hstring *key;
54953
54954                         DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
54955
54956                         tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
54957                         if (DUK_TVAL_IS_UNUSED(tv1)) {
54958                                 continue;
54959                         }
54960
54961                         DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
54962                                    new_e_pv != NULL && new_e_f != NULL);
54963
54964                         /*
54965                          *  Intern key via the valstack to ensure reachability behaves
54966                          *  properly.  We must avoid longjmp's here so use non-checked
54967                          *  primitives.
54968                          *
54969                          *  Note: duk_check_stack() potentially reallocs the valstack,
54970                          *  invalidating any duk_tval pointers to valstack.  Callers
54971                          *  must be careful.
54972                          */
54973
54974 #if 0  /* XXX: inject test */
54975                         if (1) {
54976                                 goto abandon_error;
54977                         }
54978 #endif
54979                         /* Never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which
54980                          * is generous.
54981                          */
54982                         if (!duk_check_stack(thr, 1)) {
54983                                 goto abandon_error;
54984                         }
54985                         DUK_ASSERT_VALSTACK_SPACE(thr, 1);
54986                         key = duk_heap_strtable_intern_u32(thr->heap, (duk_uint32_t) i);
54987                         if (key == NULL) {
54988                                 goto abandon_error;
54989                         }
54990                         duk_push_hstring(thr, key);  /* keep key reachable for GC etc; guaranteed not to fail */
54991
54992                         /* Key is now reachable in the valstack, don't INCREF
54993                          * the new allocation yet (we'll steal the refcounts
54994                          * from the value stack once all keys are done).
54995                          */
54996
54997                         new_e_k[new_e_next] = key;
54998                         tv2 = &new_e_pv[new_e_next].v;  /* array entries are all plain values */
54999                         DUK_TVAL_SET_TVAL(tv2, tv1);
55000                         new_e_f[new_e_next] = DUK_PROPDESC_FLAG_WRITABLE |
55001                                               DUK_PROPDESC_FLAG_ENUMERABLE |
55002                                               DUK_PROPDESC_FLAG_CONFIGURABLE;
55003                         new_e_next++;
55004
55005                         /* Note: new_e_next matches pushed temp key count, and nothing can
55006                          * fail above between the push and this point.
55007                          */
55008                 }
55009
55010                 /* Steal refcounts from value stack. */
55011                 DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next));
55012                 duk_pop_n_nodecref_unsafe(thr, (duk_idx_t) new_e_next);
55013         }
55014
55015         /*
55016          *  Copy keys and values in the entry part (compacting them at the same time).
55017          */
55018
55019         for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
55020                 duk_hstring *key;
55021
55022                 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
55023
55024                 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
55025                 if (key == NULL) {
55026                         continue;
55027                 }
55028
55029                 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
55030                            new_e_pv != NULL && new_e_f != NULL);
55031
55032                 new_e_k[new_e_next] = key;
55033                 new_e_pv[new_e_next] = DUK_HOBJECT_E_GET_VALUE(thr->heap, obj, i);
55034                 new_e_f[new_e_next] = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
55035                 new_e_next++;
55036         }
55037         /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */
55038
55039         /*
55040          *  Copy array elements to new array part.  If the new array part is
55041          *  larger, initialize the unused entries as UNUSED because they are
55042          *  GC reachable.
55043          */
55044
55045 #if defined(DUK_USE_ASSERTIONS)
55046         /* Caller must have decref'd values above new_a_size (if that is necessary). */
55047         if (!abandon_array) {
55048                 for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
55049                         duk_tval *tv;
55050                         tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
55051                         DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
55052                 }
55053         }
55054 #endif
55055         if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) {
55056                 array_copy_size = sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj);
55057         } else {
55058                 array_copy_size = sizeof(duk_tval) * new_a_size;
55059         }
55060
55061         DUK_ASSERT(new_a != NULL || array_copy_size == 0U);
55062         DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || array_copy_size == 0U);
55063         DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0 || array_copy_size == 0U);
55064         duk_memcpy_unsafe((void *) new_a,
55065                           (const void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj),
55066                           array_copy_size);
55067
55068         for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
55069                 duk_tval *tv = &new_a[i];
55070                 DUK_TVAL_SET_UNUSED(tv);
55071         }
55072
55073         /*
55074          *  Rebuild the hash part always from scratch (guaranteed to finish
55075          *  as long as caller gave consistent parameters).
55076          *
55077          *  Any resize of hash part requires rehashing.  In addition, by rehashing
55078          *  get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical
55079          *  to ensuring the hash part never fills up.
55080          */
55081
55082 #if defined(DUK_USE_HOBJECT_HASH_PART)
55083         if (new_h_size == 0) {
55084                 DUK_DDD(DUK_DDDPRINT("no hash part, no rehash"));
55085         } else {
55086                 duk_uint32_t mask;
55087
55088                 DUK_ASSERT(new_h != NULL);
55089
55090                 /* fill new_h with u32 0xff = UNUSED */
55091                 DUK_ASSERT(new_h_size > 0);
55092                 duk_memset(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
55093
55094                 DUK_ASSERT(new_e_next <= new_h_size);  /* equality not actually possible */
55095
55096                 mask = new_h_size - 1;
55097                 for (i = 0; i < new_e_next; i++) {
55098                         duk_hstring *key = new_e_k[i];
55099                         duk_uint32_t j, step;
55100
55101                         DUK_ASSERT(key != NULL);
55102                         j = DUK_HSTRING_GET_HASH(key) & mask;
55103                         step = 1;  /* Cache friendly but clustering prone. */
55104
55105                         for (;;) {
55106                                 DUK_ASSERT(new_h[j] != DUK__HASH_DELETED);  /* should never happen */
55107                                 if (new_h[j] == DUK__HASH_UNUSED) {
55108                                         DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i));
55109                                         new_h[j] = (duk_uint32_t) i;
55110                                         break;
55111                                 }
55112                                 DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step));
55113                                 j = (j + step) & mask;
55114
55115                                 /* Guaranteed to finish (hash is larger than #props). */
55116                         }
55117                 }
55118         }
55119 #endif  /* DUK_USE_HOBJECT_HASH_PART */
55120
55121         /*
55122          *  Nice debug log.
55123          */
55124
55125         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 "
55126                            "{p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
55127                            (void *) obj,
55128                            (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
55129                                                              DUK_HOBJECT_GET_ASIZE(obj),
55130                                                              DUK_HOBJECT_GET_HSIZE(obj)),
55131                            (long) new_alloc_size,
55132                            (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
55133                            (long) DUK_HOBJECT_GET_ESIZE(obj),
55134                            (long) DUK_HOBJECT_GET_ENEXT(obj),
55135                            (long) DUK_HOBJECT_GET_ASIZE(obj),
55136                            (long) DUK_HOBJECT_GET_HSIZE(obj),
55137                            (void *) new_p,
55138                            (long) new_e_size_adjusted,
55139                            (long) new_e_next,
55140                            (long) new_a_size,
55141                            (long) new_h_size,
55142                            (long) abandon_array,
55143                            (long) new_e_size));
55144
55145         /*
55146          *  All done, switch properties ('p') allocation to new one.
55147          */
55148
55149         DUK_FREE_CHECKED(thr, DUK_HOBJECT_GET_PROPS(thr->heap, obj));  /* NULL obj->p is OK */
55150         DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p);
55151         DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted);
55152         DUK_HOBJECT_SET_ENEXT(obj, new_e_next);
55153         DUK_HOBJECT_SET_ASIZE(obj, new_a_size);
55154         DUK_HOBJECT_SET_HSIZE(obj, new_h_size);
55155
55156         /* Clear array part flag only after switching. */
55157         if (abandon_array) {
55158                 DUK_HOBJECT_CLEAR_ARRAY_PART(obj);
55159         }
55160
55161         DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj));
55162
55163         DUK_ASSERT(thr->heap->pf_prevent_count > 0);
55164         thr->heap->pf_prevent_count--;
55165         thr->heap->ms_base_flags = prev_ms_base_flags;
55166 #if defined(DUK_USE_ASSERTIONS)
55167         DUK_ASSERT(thr->heap->error_not_allowed == 1);
55168         thr->heap->error_not_allowed = prev_error_not_allowed;
55169 #endif
55170
55171         /*
55172          *  Post resize assertions.
55173          */
55174
55175 #if defined(DUK_USE_ASSERTIONS)
55176         /* XXX: post-checks (such as no duplicate keys) */
55177 #endif
55178         return;
55179
55180         /*
55181          *  Abandon array failed.  We don't need to DECREF anything
55182          *  because the references in the new allocation are not
55183          *  INCREF'd until abandon is complete.  The string interned
55184          *  keys are on the value stack and are handled normally by
55185          *  unwind.
55186          */
55187
55188  abandon_error:
55189  alloc_failed:
55190         DUK_D(DUK_DPRINT("object property table resize failed"));
55191
55192         DUK_FREE_CHECKED(thr, new_p);  /* OK for NULL. */
55193
55194         thr->heap->pf_prevent_count--;
55195         thr->heap->ms_base_flags = prev_ms_base_flags;
55196 #if defined(DUK_USE_ASSERTIONS)
55197         DUK_ASSERT(thr->heap->error_not_allowed == 1);
55198         thr->heap->error_not_allowed = prev_error_not_allowed;
55199 #endif
55200
55201         DUK_ERROR_ALLOC_FAILED(thr);
55202         DUK_WO_NORETURN(return;);
55203 }
55204
55205 /*
55206  *  Helpers to resize properties allocation on specific needs.
55207  */
55208
55209 DUK_INTERNAL void duk_hobject_resize_entrypart(duk_hthread *thr,
55210                                                duk_hobject *obj,
55211                                                duk_uint32_t new_e_size) {
55212         duk_uint32_t old_e_size;
55213         duk_uint32_t new_a_size;
55214         duk_uint32_t new_h_size;
55215
55216         DUK_ASSERT(thr != NULL);
55217         DUK_ASSERT(obj != NULL);
55218
55219         old_e_size = DUK_HOBJECT_GET_ESIZE(obj);
55220         if (old_e_size > new_e_size) {
55221                 new_e_size = old_e_size;
55222         }
55223 #if defined(DUK_USE_HOBJECT_HASH_PART)
55224         new_h_size = duk__get_default_h_size(new_e_size);
55225 #else
55226         new_h_size = 0;
55227 #endif
55228         new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
55229
55230         duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
55231 }
55232
55233 #if 0  /*unused */
55234 DUK_INTERNAL void duk_hobject_resize_arraypart(duk_hthread *thr,
55235                                                duk_hobject *obj,
55236                                                duk_uint32_t new_a_size) {
55237         duk_uint32_t old_a_size;
55238         duk_uint32_t new_e_size;
55239         duk_uint32_t new_h_size;
55240
55241         DUK_ASSERT(thr != NULL);
55242         DUK_ASSERT(obj != NULL);
55243
55244         if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
55245                 return;
55246         }
55247         old_a_size = DUK_HOBJECT_GET_ASIZE(obj);
55248         if (old_a_size > new_a_size) {
55249                 new_a_size = old_a_size;
55250         }
55251         new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
55252         new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
55253
55254         duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
55255 }
55256 #endif
55257
55258 /* Grow entry part allocation for one additional entry. */
55259 DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
55260         duk_uint32_t old_e_used;  /* actually used, non-NULL entries */
55261         duk_uint32_t new_e_size;
55262         duk_uint32_t new_a_size;
55263         duk_uint32_t new_h_size;
55264
55265         DUK_ASSERT(thr != NULL);
55266         DUK_ASSERT(obj != NULL);
55267
55268         /* Duktape 0.11.0 and prior tried to optimize the resize by not
55269          * counting the number of actually used keys prior to the resize.
55270          * This worked mostly well but also caused weird leak-like behavior
55271          * as in: test-bug-object-prop-alloc-unbounded.js.  So, now we count
55272          * the keys explicitly to compute the new entry part size.
55273          */
55274
55275         old_e_used = duk__count_used_e_keys(thr, obj);
55276         new_e_size = old_e_used + duk__get_min_grow_e(old_e_used);
55277 #if defined(DUK_USE_HOBJECT_HASH_PART)
55278         new_h_size = duk__get_default_h_size(new_e_size);
55279 #else
55280         new_h_size = 0;
55281 #endif
55282         new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
55283         DUK_ASSERT(new_e_size >= old_e_used + 1);  /* duk__get_min_grow_e() is always >= 1 */
55284
55285         duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
55286 }
55287
55288 /* Grow array part for a new highest array index. */
55289 DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) {
55290         duk_uint32_t new_e_size;
55291         duk_uint32_t new_a_size;
55292         duk_uint32_t new_h_size;
55293
55294         DUK_ASSERT(thr != NULL);
55295         DUK_ASSERT(obj != NULL);
55296         DUK_ASSERT(highest_arr_idx >= DUK_HOBJECT_GET_ASIZE(obj));
55297
55298         /* minimum new length is highest_arr_idx + 1 */
55299
55300         new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
55301         new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
55302         new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx);
55303         DUK_ASSERT(new_a_size >= highest_arr_idx + 1);  /* duk__get_min_grow_a() is always >= 1 */
55304
55305         duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
55306 }
55307
55308 /* Abandon array part, moving array entries into entries part.
55309  * This requires a props resize, which is a heavy operation.
55310  * We also compact the entries part while we're at it, although
55311  * this is not strictly required.
55312  */
55313 DUK_LOCAL void duk__abandon_array_checked(duk_hthread *thr, duk_hobject *obj) {
55314         duk_uint32_t new_e_size;
55315         duk_uint32_t new_a_size;
55316         duk_uint32_t new_h_size;
55317         duk_uint32_t e_used;  /* actually used, non-NULL keys */
55318         duk_uint32_t a_used;
55319         duk_uint32_t a_size;
55320
55321         DUK_ASSERT(thr != NULL);
55322         DUK_ASSERT(obj != NULL);
55323
55324         e_used = duk__count_used_e_keys(thr, obj);
55325         duk__compute_a_stats(thr, obj, &a_used, &a_size);
55326
55327         /*
55328          *  Must guarantee all actually used array entries will fit into
55329          *  new entry part.  Add one growth step to ensure we don't run out
55330          *  of space right away.
55331          */
55332
55333         new_e_size = e_used + a_used;
55334         new_e_size = new_e_size + duk__get_min_grow_e(new_e_size);
55335         new_a_size = 0;
55336 #if defined(DUK_USE_HOBJECT_HASH_PART)
55337         new_h_size = duk__get_default_h_size(new_e_size);
55338 #else
55339         new_h_size = 0;
55340 #endif
55341
55342         DUK_DD(DUK_DDPRINT("abandon array part for hobject %p, "
55343                            "array stats before: e_used=%ld, a_used=%ld, a_size=%ld; "
55344                            "resize to e_size=%ld, a_size=%ld, h_size=%ld",
55345                            (void *) obj, (long) e_used, (long) a_used, (long) a_size,
55346                            (long) new_e_size, (long) new_a_size, (long) new_h_size));
55347
55348         duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
55349 }
55350
55351 /*
55352  *  Compact an object.  Minimizes allocation size for objects which are
55353  *  not likely to be extended.  This is useful for internal and non-
55354  *  extensible objects, but can also be called for non-extensible objects.
55355  *  May abandon the array part if it is computed to be too sparse.
55356  *
55357  *  This call is relatively expensive, as it needs to scan both the
55358  *  entries and the array part.
55359  *
55360  *  The call may fail due to allocation error.
55361  */
55362
55363 DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) {
55364         duk_uint32_t e_size;       /* currently used -> new size */
55365         duk_uint32_t a_size;       /* currently required */
55366         duk_uint32_t a_used;       /* actually used */
55367         duk_uint32_t h_size;
55368         duk_bool_t abandon_array;
55369
55370         DUK_ASSERT(thr != NULL);
55371         DUK_ASSERT(obj != NULL);
55372
55373 #if defined(DUK_USE_ROM_OBJECTS)
55374         if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
55375                 DUK_DD(DUK_DDPRINT("ignore attempt to compact a rom object"));
55376                 return;
55377         }
55378 #endif
55379
55380         e_size = duk__count_used_e_keys(thr, obj);
55381         duk__compute_a_stats(thr, obj, &a_used, &a_size);
55382
55383         DUK_DD(DUK_DDPRINT("compacting hobject, used e keys %ld, used a keys %ld, min a size %ld, "
55384                            "resized array density would be: %ld/%ld = %lf",
55385                            (long) e_size, (long) a_used, (long) a_size,
55386                            (long) a_used, (long) a_size,
55387                            (double) a_used / (double) a_size));
55388
55389         if (duk__abandon_array_density_check(a_used, a_size)) {
55390                 DUK_DD(DUK_DDPRINT("decided to abandon array during compaction, a_used=%ld, a_size=%ld",
55391                                    (long) a_used, (long) a_size));
55392                 abandon_array = 1;
55393                 e_size += a_used;
55394                 a_size = 0;
55395         } else {
55396                 DUK_DD(DUK_DDPRINT("decided to keep array during compaction"));
55397                 abandon_array = 0;
55398         }
55399
55400 #if defined(DUK_USE_HOBJECT_HASH_PART)
55401         if (e_size >= DUK_USE_HOBJECT_HASH_PROP_LIMIT) {
55402                 h_size = duk__get_default_h_size(e_size);
55403         } else {
55404                 h_size = 0;
55405         }
55406 #else
55407         h_size = 0;
55408 #endif
55409
55410         DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld",
55411                            (long) e_size, (long) a_size, (long) h_size, (long) abandon_array));
55412
55413         duk_hobject_realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
55414 }
55415
55416 /*
55417  *  Find an existing key from entry part either by linear scan or by
55418  *  using the hash index (if it exists).
55419  *
55420  *  Sets entry index (and possibly the hash index) to output variables,
55421  *  which allows the caller to update the entry and hash entries in-place.
55422  *  If entry is not found, both values are set to -1.  If entry is found
55423  *  but there is no hash part, h_idx is set to -1.
55424  */
55425
55426 DUK_INTERNAL duk_bool_t duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) {
55427         DUK_ASSERT(obj != NULL);
55428         DUK_ASSERT(key != NULL);
55429         DUK_ASSERT(e_idx != NULL);
55430         DUK_ASSERT(h_idx != NULL);
55431         DUK_UNREF(heap);
55432
55433         if (DUK_LIKELY(DUK_HOBJECT_GET_HSIZE(obj) == 0))
55434         {
55435                 /* Linear scan: more likely because most objects are small.
55436                  * This is an important fast path.
55437                  *
55438                  * XXX: this might be worth inlining for property lookups.
55439                  */
55440                 duk_uint_fast32_t i;
55441                 duk_uint_fast32_t n;
55442                 duk_hstring **h_keys_base;
55443                 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using linear scan for lookup"));
55444
55445                 h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(heap, obj);
55446                 n = DUK_HOBJECT_GET_ENEXT(obj);
55447                 for (i = 0; i < n; i++) {
55448                         if (h_keys_base[i] == key) {
55449                                 *e_idx = (duk_int_t) i;
55450                                 *h_idx = -1;
55451                                 return 1;
55452                         }
55453                 }
55454         }
55455 #if defined(DUK_USE_HOBJECT_HASH_PART)
55456         else
55457         {
55458                 /* hash lookup */
55459                 duk_uint32_t n;
55460                 duk_uint32_t i, step;
55461                 duk_uint32_t *h_base;
55462                 duk_uint32_t mask;
55463
55464                 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup"));
55465
55466                 h_base = DUK_HOBJECT_H_GET_BASE(heap, obj);
55467                 n = DUK_HOBJECT_GET_HSIZE(obj);
55468                 mask = n - 1;
55469                 i = DUK_HSTRING_GET_HASH(key) & mask;
55470                 step = 1;  /* Cache friendly but clustering prone. */
55471
55472                 for (;;) {
55473                         duk_uint32_t t;
55474
55475                         DUK_ASSERT_DISABLE(i >= 0);  /* unsigned */
55476                         DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
55477                         t = h_base[i];
55478                         DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED ||
55479                                    (t < DUK_HOBJECT_GET_ESIZE(obj)));  /* t >= 0 always true, unsigned */
55480
55481                         if (t == DUK__HASH_UNUSED) {
55482                                 break;
55483                         } else if (t == DUK__HASH_DELETED) {
55484                                 DUK_DDD(DUK_DDDPRINT("lookup miss (deleted) i=%ld, t=%ld",
55485                                                      (long) i, (long) t));
55486                         } else {
55487                                 DUK_ASSERT(t < DUK_HOBJECT_GET_ESIZE(obj));
55488                                 if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) {
55489                                         DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p",
55490                                                              (long) i, (long) t, (void *) key));
55491                                         *e_idx = (duk_int_t) t;
55492                                         *h_idx = (duk_int_t) i;
55493                                         return 1;
55494                                 }
55495                                 DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld",
55496                                                      (long) i, (long) t));
55497                         }
55498                         i = (i + step) & mask;
55499
55500                         /* Guaranteed to finish (hash is larger than #props). */
55501                 }
55502         }
55503 #endif  /* DUK_USE_HOBJECT_HASH_PART */
55504
55505         /* Not found, leave e_idx and h_idx unset. */
55506         return 0;
55507 }
55508
55509 /* For internal use: get non-accessor entry value */
55510 DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key) {
55511         duk_int_t e_idx;
55512         duk_int_t h_idx;
55513
55514         DUK_ASSERT(obj != NULL);
55515         DUK_ASSERT(key != NULL);
55516         DUK_UNREF(heap);
55517
55518         if (duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx)) {
55519                 DUK_ASSERT(e_idx >= 0);
55520                 if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
55521                         return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
55522                 }
55523         }
55524         return NULL;
55525 }
55526
55527 /* For internal use: get non-accessor entry value and attributes */
55528 DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_uint_t *out_attrs) {
55529         duk_int_t e_idx;
55530         duk_int_t h_idx;
55531
55532         DUK_ASSERT(obj != NULL);
55533         DUK_ASSERT(key != NULL);
55534         DUK_ASSERT(out_attrs != NULL);
55535         DUK_UNREF(heap);
55536
55537         if (duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx)) {
55538                 DUK_ASSERT(e_idx >= 0);
55539                 if (!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
55540                         *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
55541                         return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
55542                 }
55543         }
55544         /* If not found, out_attrs is left unset. */
55545         return NULL;
55546 }
55547
55548 /* For internal use: get array part value */
55549 DUK_INTERNAL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i) {
55550         duk_tval *tv;
55551
55552         DUK_ASSERT(obj != NULL);
55553         DUK_UNREF(heap);
55554
55555         if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
55556                 return NULL;
55557         }
55558         if (i >= DUK_HOBJECT_GET_ASIZE(obj)) {
55559                 return NULL;
55560         }
55561         tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, obj, i);
55562         return tv;
55563 }
55564
55565 /*
55566  *  Allocate and initialize a new entry, resizing the properties allocation
55567  *  if necessary.  Returns entry index (e_idx) or throws an error if alloc fails.
55568  *
55569  *  Sets the key of the entry (increasing the key's refcount), and updates
55570  *  the hash part if it exists.  Caller must set value and flags, and update
55571  *  the entry value refcount.  A decref for the previous value is not necessary.
55572  */
55573
55574 DUK_LOCAL duk_int_t duk__hobject_alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
55575         duk_uint32_t idx;
55576
55577         DUK_ASSERT(thr != NULL);
55578         DUK_ASSERT(obj != NULL);
55579         DUK_ASSERT(key != NULL);
55580         DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj));
55581
55582 #if defined(DUK_USE_ASSERTIONS)
55583         /* key must not already exist in entry part */
55584         {
55585                 duk_uint_fast32_t i;
55586                 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
55587                         DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != key);
55588                 }
55589         }
55590 #endif
55591
55592         if (DUK_HOBJECT_GET_ENEXT(obj) >= DUK_HOBJECT_GET_ESIZE(obj)) {
55593                 /* only need to guarantee 1 more slot, but allocation growth is in chunks */
55594                 DUK_DDD(DUK_DDDPRINT("entry part full, allocate space for one more entry"));
55595                 duk__grow_props_for_new_entry_item(thr, obj);
55596         }
55597         DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) < DUK_HOBJECT_GET_ESIZE(obj));
55598         idx = DUK_HOBJECT_POSTINC_ENEXT(obj);
55599
55600         /* previous value is assumed to be garbage, so don't touch it */
55601         DUK_HOBJECT_E_SET_KEY(thr->heap, obj, idx, key);
55602         DUK_HSTRING_INCREF(thr, key);
55603
55604 #if defined(DUK_USE_HOBJECT_HASH_PART)
55605         if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) {
55606                 duk_uint32_t n, mask;
55607                 duk_uint32_t i, step;
55608                 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
55609
55610                 n = DUK_HOBJECT_GET_HSIZE(obj);
55611                 mask = n - 1;
55612                 i = DUK_HSTRING_GET_HASH(key) & mask;
55613                 step = 1;  /* Cache friendly but clustering prone. */
55614
55615                 for (;;) {
55616                         duk_uint32_t t = h_base[i];
55617                         if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
55618                                 DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() inserted key into hash part, %ld -> %ld",
55619                                                      (long) i, (long) idx));
55620                                 DUK_ASSERT_DISABLE(i >= 0);  /* unsigned */
55621                                 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
55622                                 DUK_ASSERT_DISABLE(idx >= 0);
55623                                 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
55624                                 h_base[i] = idx;
55625                                 break;
55626                         }
55627                         DUK_DDD(DUK_DDDPRINT("duk__hobject_alloc_entry_checked() miss %ld", (long) i));
55628                         i = (i + step) & mask;
55629
55630                         /* Guaranteed to finish (hash is larger than #props). */
55631                 }
55632         }
55633 #endif  /* DUK_USE_HOBJECT_HASH_PART */
55634
55635         /* Note: we could return the hash index here too, but it's not
55636          * needed right now.
55637          */
55638
55639         DUK_ASSERT_DISABLE(idx >= 0);
55640         DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
55641         DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj));
55642         return (duk_int_t) idx;
55643 }
55644
55645 /*
55646  *  Object internal value
55647  *
55648  *  Returned value is guaranteed to be reachable / incref'd, caller does not need
55649  *  to incref OR decref.  No proxies or accessors are invoked, no prototype walk.
55650  */
55651
55652 DUK_INTERNAL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv_out) {
55653         duk_int_t e_idx;
55654         duk_int_t h_idx;
55655
55656         DUK_ASSERT(heap != NULL);
55657         DUK_ASSERT(obj != NULL);
55658         DUK_ASSERT(tv_out != NULL);
55659
55660         /* Always in entry part, no need to look up parents etc. */
55661         if (duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx)) {
55662                 DUK_ASSERT(e_idx >= 0);
55663                 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx));
55664                 DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx));
55665                 return 1;
55666         }
55667         DUK_TVAL_SET_UNDEFINED(tv_out);
55668         return 0;
55669 }
55670
55671 DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) {
55672         duk_tval tv;
55673
55674         DUK_ASSERT(heap != NULL);
55675         DUK_ASSERT(obj != NULL);
55676
55677         /* This is not strictly necessary, but avoids compiler warnings; e.g.
55678          * gcc won't reliably detect that no uninitialized data is read below.
55679          */
55680         duk_memzero((void *) &tv, sizeof(duk_tval));
55681
55682         if (duk_hobject_get_internal_value(heap, obj, &tv)) {
55683                 duk_hstring *h;
55684                 DUK_ASSERT(DUK_TVAL_IS_STRING(&tv));
55685                 h = DUK_TVAL_GET_STRING(&tv);
55686                 /* No explicit check for string vs. symbol, accept both. */
55687                 return h;
55688         }
55689
55690         return NULL;
55691 }
55692
55693 /*
55694  *  Arguments handling helpers (argument map mainly).
55695  *
55696  *  An arguments object has exotic behavior for some numeric indices.
55697  *  Accesses may translate to identifier operations which may have
55698  *  arbitrary side effects (potentially invalidating any duk_tval
55699  *  pointers).
55700  */
55701
55702 /* Lookup 'key' from arguments internal 'map', perform a variable lookup
55703  * if mapped, and leave the result on top of stack (and return non-zero).
55704  * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]].
55705  */
55706 DUK_LOCAL
55707 duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
55708                                      duk_hobject *obj,
55709                                      duk_hstring *key,
55710                                      duk_propdesc *temp_desc,
55711                                      duk_hobject **out_map,
55712                                      duk_hobject **out_varenv) {
55713         duk_hobject *map;
55714         duk_hobject *varenv;
55715         duk_bool_t rc;
55716
55717         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
55718
55719         DUK_DDD(DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p "
55720                              "(obj -> %!O, key -> %!O)",
55721                              (void *) thr, (void *) obj, (void *) key, (void *) temp_desc,
55722                              (duk_heaphdr *) obj, (duk_heaphdr *) key));
55723
55724         if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
55725                 DUK_DDD(DUK_DDDPRINT("-> no 'map'"));
55726                 return 0;
55727         }
55728
55729         map = duk_require_hobject(thr, -1);
55730         DUK_ASSERT(map != NULL);
55731         duk_pop_unsafe(thr);  /* map is reachable through obj */
55732
55733         if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
55734                 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map"));
55735                 return 0;
55736         }
55737
55738         /* [... varname] */
55739         DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
55740                              (duk_tval *) duk_get_tval(thr, -1)));
55741         DUK_ASSERT(duk_is_string(thr, -1));  /* guaranteed when building arguments */
55742
55743         /* get varenv for varname (callee's declarative lexical environment) */
55744         rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE);
55745         DUK_UNREF(rc);
55746         DUK_ASSERT(rc != 0);  /* arguments MUST have an initialized lexical environment reference */
55747         varenv = duk_require_hobject(thr, -1);
55748         DUK_ASSERT(varenv != NULL);
55749         duk_pop_unsafe(thr);  /* varenv remains reachable through 'obj' */
55750
55751         DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv));
55752
55753         /* success: leave varname in stack */
55754         *out_map = map;
55755         *out_varenv = varenv;
55756         return 1;  /* [... varname] */
55757 }
55758
55759 /* Lookup 'key' from arguments internal 'map', and leave replacement value
55760  * on stack top if mapped (and return non-zero).
55761  * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
55762  */
55763 DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
55764         duk_hobject *map;
55765         duk_hobject *varenv;
55766         duk_hstring *varname;
55767
55768         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
55769
55770         if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
55771                 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic get behavior"));
55772                 return 0;
55773         }
55774
55775         /* [... varname] */
55776
55777         varname = duk_require_hstring(thr, -1);
55778         DUK_ASSERT(varname != NULL);
55779         duk_pop_unsafe(thr);  /* varname is still reachable */
55780
55781         DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
55782                              "key=%!O, varname=%!O",
55783                              (duk_heaphdr *) key,
55784                              (duk_heaphdr *) varname));
55785
55786         (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/);
55787
55788         /* [... value this_binding] */
55789
55790         duk_pop_unsafe(thr);
55791
55792         /* leave result on stack top */
55793         return 1;
55794 }
55795
55796 /* Lookup 'key' from arguments internal 'map', perform a variable write if mapped.
55797  * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]).
55798  * Assumes stack top contains 'put' value (which is NOT popped).
55799  */
55800 DUK_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) {
55801         duk_hobject *map;
55802         duk_hobject *varenv;
55803         duk_hstring *varname;
55804
55805         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
55806
55807         if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
55808                 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic put behavior"));
55809                 return;
55810         }
55811
55812         /* [... put_value varname] */
55813
55814         varname = duk_require_hstring(thr, -1);
55815         DUK_ASSERT(varname != NULL);
55816         duk_pop_unsafe(thr);  /* varname is still reachable */
55817
55818         DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
55819                              "key=%!O, varname=%!O, value=%!T",
55820                              (duk_heaphdr *) key,
55821                              (duk_heaphdr *) varname,
55822                              (duk_tval *) duk_require_tval(thr, -1)));
55823
55824         /* [... put_value] */
55825
55826         /*
55827          *  Note: although arguments object variable mappings are only established
55828          *  for non-strict functions (and a call to a non-strict function created
55829          *  the arguments object in question), an inner strict function may be doing
55830          *  the actual property write.  Hence the throw_flag applied here comes from
55831          *  the property write call.
55832          */
55833
55834         duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, -1), throw_flag);
55835
55836         /* [... put_value] */
55837 }
55838
55839 /* Lookup 'key' from arguments internal 'map', delete mapping if found.
55840  * Used in E5 Section 10.6 algorithm for [[Delete]].  Note that the
55841  * variable/argument itself (where the map points) is not deleted.
55842  */
55843 DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
55844         duk_hobject *map;
55845
55846         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
55847
55848         if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
55849                 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior"));
55850                 return;
55851         }
55852
55853         map = duk_require_hobject(thr, -1);
55854         DUK_ASSERT(map != NULL);
55855         duk_pop_unsafe(thr);  /* map is reachable through obj */
55856
55857         DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result",
55858                              (duk_heaphdr *) key));
55859
55860         /* Note: no recursion issue, we can trust 'map' to behave */
55861         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(map));
55862         DUK_DDD(DUK_DDDPRINT("map before deletion: %!O", (duk_heaphdr *) map));
55863         (void) duk_hobject_delprop_raw(thr, map, key, 0);  /* ignore result */
55864         DUK_DDD(DUK_DDDPRINT("map after deletion: %!O", (duk_heaphdr *) map));
55865 }
55866
55867 /*
55868  *  ECMAScript compliant [[GetOwnProperty]](P), for internal use only.
55869  *
55870  *  If property is found:
55871  *    - Fills descriptor fields to 'out_desc'
55872  *    - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
55873  *      property onto the stack ('undefined' for accessor properties).
55874  *    - Returns non-zero
55875  *
55876  *  If property is not found:
55877  *    - 'out_desc' is left in untouched state (possibly garbage)
55878  *    - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
55879  *      set)
55880  *    - Returns zero
55881  *
55882  *  Notes:
55883  *
55884  *    - Getting a property descriptor may cause an allocation (and hence
55885  *      GC) to take place, hence reachability and refcount of all related
55886  *      values matter.  Reallocation of value stack, properties, etc may
55887  *      invalidate many duk_tval pointers (concretely, those which reside
55888  *      in memory areas subject to reallocation).  However, heap object
55889  *      pointers are never affected (heap objects have stable pointers).
55890  *
55891  *    - The value of a plain property is always reachable and has a non-zero
55892  *      reference count.
55893  *
55894  *    - The value of a virtual property is not necessarily reachable from
55895  *      elsewhere and may have a refcount of zero.  Hence we push it onto
55896  *      the valstack for the caller, which ensures it remains reachable
55897  *      while it is needed.
55898  *
55899  *    - There are no virtual accessor properties.  Hence, all getters and
55900  *      setters are always related to concretely stored properties, which
55901  *      ensures that the get/set functions in the resulting descriptor are
55902  *      reachable and have non-zero refcounts.  Should there be virtual
55903  *      accessor properties later, this would need to change.
55904  */
55905
55906 DUK_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) {
55907         duk_tval *tv;
55908
55909         DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
55910                              "arr_idx=%ld (obj -> %!O, key -> %!O)",
55911                              (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
55912                              (long) flags, (long) arr_idx,
55913                              (duk_heaphdr *) obj, (duk_heaphdr *) key));
55914
55915         DUK_ASSERT(thr != NULL);
55916         DUK_ASSERT(thr->heap != NULL);
55917         DUK_ASSERT(obj != NULL);
55918         DUK_ASSERT(key != NULL);
55919         DUK_ASSERT(out_desc != NULL);
55920         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
55921
55922         DUK_STATS_INC(thr->heap, stats_getownpropdesc_count);
55923
55924         /* Each code path returning 1 (= found) must fill in all the output
55925          * descriptor fields.  We don't do it beforehand because it'd be
55926          * unnecessary work if the property isn't found and would happen
55927          * multiple times for an inheritance chain.
55928          */
55929         DUK_ASSERT_SET_GARBAGE(out_desc, sizeof(*out_desc));
55930 #if 0
55931         out_desc->flags = 0;
55932         out_desc->get = NULL;
55933         out_desc->set = NULL;
55934         out_desc->e_idx = -1;
55935         out_desc->h_idx = -1;
55936         out_desc->a_idx = -1;
55937 #endif
55938
55939         /*
55940          *  Try entries part first because it's the common case.
55941          *
55942          *  Array part lookups are usually handled by the array fast path, and
55943          *  are not usually inherited.  Array and entry parts never contain the
55944          *  same keys so the entry part vs. array part order doesn't matter.
55945          */
55946
55947         if (duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx)) {
55948                 duk_int_t e_idx = out_desc->e_idx;
55949                 DUK_ASSERT(out_desc->e_idx >= 0);
55950                 out_desc->a_idx = -1;
55951                 out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx);
55952                 out_desc->get = NULL;
55953                 out_desc->set = NULL;
55954                 if (DUK_UNLIKELY(out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR)) {
55955                         DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part"));
55956                         out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx);
55957                         out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx);
55958                         if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
55959                                 /* a dummy undefined value is pushed to make valstack
55960                                  * behavior uniform for caller
55961                                  */
55962                                 duk_push_undefined(thr);
55963                         }
55964                 } else {
55965                         DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part"));
55966                         tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
55967                         if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
55968                                 duk_push_tval(thr, tv);
55969                         }
55970                 }
55971                 goto prop_found;
55972         }
55973
55974         /*
55975          *  Try array part.
55976          */
55977
55978         if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
55979                 if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
55980                         tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
55981                         if (!DUK_TVAL_IS_UNUSED(tv)) {
55982                                 DUK_DDD(DUK_DDDPRINT("-> found in array part"));
55983                                 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
55984                                         duk_push_tval(thr, tv);
55985                                 }
55986                                 /* implicit attributes */
55987                                 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
55988                                                   DUK_PROPDESC_FLAG_CONFIGURABLE |
55989                                                   DUK_PROPDESC_FLAG_ENUMERABLE;
55990                                 out_desc->get = NULL;
55991                                 out_desc->set = NULL;
55992                                 out_desc->e_idx = -1;
55993                                 out_desc->h_idx = -1;
55994                                 out_desc->a_idx = (duk_int_t) arr_idx;  /* XXX: limit 2G due to being signed */
55995                                 goto prop_found;
55996                         }
55997                 }
55998         }
55999
56000         DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property"));
56001
56002         /*
56003          *  Not found as a concrete property, check for virtual properties.
56004          */
56005
56006         if (!DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(obj)) {
56007                 /* Quick skip. */
56008                 goto prop_not_found;
56009         }
56010
56011         if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
56012                 duk_harray *a;
56013
56014                 DUK_DDD(DUK_DDDPRINT("array object exotic property get for key: %!O, arr_idx: %ld",
56015                                      (duk_heaphdr *) key, (long) arr_idx));
56016
56017                 a = (duk_harray *) obj;
56018                 DUK_ASSERT_HARRAY_VALID(a);
56019
56020                 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
56021                         DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
56022
56023                         if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
56024                                 duk_push_uint(thr, (duk_uint_t) a->length);
56025                         }
56026                         out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
56027                         if (DUK_HARRAY_LENGTH_WRITABLE(a)) {
56028                                 out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE;
56029                         }
56030                         out_desc->get = NULL;
56031                         out_desc->set = NULL;
56032                         out_desc->e_idx = -1;
56033                         out_desc->h_idx = -1;
56034                         out_desc->a_idx = -1;
56035
56036                         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
56037                         goto prop_found_noexotic;  /* cannot be arguments exotic */
56038                 }
56039         } else if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
56040                 DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld",
56041                                      (duk_heaphdr *) key, (long) arr_idx));
56042
56043                 /* XXX: charlen; avoid multiple lookups? */
56044
56045                 if (arr_idx != DUK__NO_ARRAY_INDEX) {
56046                         duk_hstring *h_val;
56047
56048                         DUK_DDD(DUK_DDDPRINT("array index exists"));
56049
56050                         h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
56051                         DUK_ASSERT(h_val);
56052                         if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
56053                                 DUK_DDD(DUK_DDDPRINT("-> found, array index inside string"));
56054                                 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
56055                                         duk_push_hstring(thr, h_val);
56056                                         duk_substring(thr, -1, arr_idx, arr_idx + 1);  /* [str] -> [substr] */
56057                                 }
56058                                 out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE |  /* E5 Section 15.5.5.2 */
56059                                                   DUK_PROPDESC_FLAG_VIRTUAL;
56060                                 out_desc->get = NULL;
56061                                 out_desc->set = NULL;
56062                                 out_desc->e_idx = -1;
56063                                 out_desc->h_idx = -1;
56064                                 out_desc->a_idx = -1;
56065
56066                                 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
56067                                 goto prop_found_noexotic;  /* cannot be arguments exotic */
56068                         } else {
56069                                 /* index is above internal string length -> property is fully normal */
56070                                 DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property"));
56071                         }
56072                 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
56073                         duk_hstring *h_val;
56074
56075                         DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
56076
56077                         h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
56078                         DUK_ASSERT(h_val != NULL);
56079                         if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
56080                                 duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
56081                         }
56082                         out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;  /* E5 Section 15.5.5.1 */
56083                         out_desc->get = NULL;
56084                         out_desc->set = NULL;
56085                         out_desc->e_idx = -1;
56086                         out_desc->h_idx = -1;
56087                         out_desc->a_idx = -1;
56088
56089                         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
56090                         goto prop_found_noexotic;  /* cannot be arguments exotic */
56091                 }
56092         }
56093 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
56094         else if (DUK_HOBJECT_IS_BUFOBJ(obj)) {
56095                 duk_hbufobj *h_bufobj;
56096                 duk_uint_t byte_off;
56097                 duk_small_uint_t elem_size;
56098
56099                 h_bufobj = (duk_hbufobj *) obj;
56100                 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
56101                 DUK_DDD(DUK_DDDPRINT("bufobj property get for key: %!O, arr_idx: %ld",
56102                                      (duk_heaphdr *) key, (long) arr_idx));
56103
56104                 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
56105                         DUK_DDD(DUK_DDDPRINT("array index exists"));
56106
56107                         /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
56108                          * length downshift won't.
56109                          */
56110                         if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
56111                                 byte_off = arr_idx << h_bufobj->shift;  /* no wrap assuming h_bufobj->length is valid */
56112                                 elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
56113                                 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
56114                                         duk_uint8_t *data;
56115
56116                                         if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
56117                                                 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
56118                                                 duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size);
56119                                         } else {
56120                                                 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
56121                                                 duk_push_uint(thr, 0);
56122                                         }
56123                                 }
56124                                 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
56125                                                   DUK_PROPDESC_FLAG_VIRTUAL;
56126                                 if (DUK_HOBJECT_GET_CLASS_NUMBER(obj) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
56127                                         /* ArrayBuffer indices are non-standard and are
56128                                          * non-enumerable to avoid their serialization.
56129                                          */
56130                                         out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
56131                                 }
56132                                 out_desc->get = NULL;
56133                                 out_desc->set = NULL;
56134                                 out_desc->e_idx = -1;
56135                                 out_desc->h_idx = -1;
56136                                 out_desc->a_idx = -1;
56137
56138                                 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
56139                                 goto prop_found_noexotic;  /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
56140                         } else {
56141                                 /* index is above internal buffer length -> property is fully normal */
56142                                 DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property"));
56143                         }
56144                 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
56145                         DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
56146
56147                         if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
56148                                 /* Length in elements: take into account shift, but
56149                                  * intentionally don't check the underlying buffer here.
56150                                  */
56151                                 duk_push_uint(thr, h_bufobj->length >> h_bufobj->shift);
56152                         }
56153                         out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
56154                         out_desc->get = NULL;
56155                         out_desc->set = NULL;
56156                         out_desc->e_idx = -1;
56157                         out_desc->h_idx = -1;
56158                         out_desc->a_idx = -1;
56159
56160                         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
56161                         goto prop_found_noexotic;  /* cannot be arguments exotic */
56162                 }
56163         }
56164 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
56165
56166         /* Array properties have exotic behavior but they are concrete,
56167          * so no special handling here.
56168          *
56169          * Arguments exotic behavior (E5 Section 10.6, [[GetOwnProperty]]
56170          * is only relevant as a post-check implemented below; hence no
56171          * check here.
56172          */
56173
56174         /*
56175          *  Not found as concrete or virtual.
56176          */
56177
56178  prop_not_found:
56179         DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)"));
56180         DUK_STATS_INC(thr->heap, stats_getownpropdesc_miss);
56181         return 0;
56182
56183         /*
56184          *  Found.
56185          *
56186          *  Arguments object has exotic post-processing, see E5 Section 10.6,
56187          *  description of [[GetOwnProperty]] variant for arguments.
56188          */
56189
56190  prop_found:
56191         DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior"));
56192
56193         /* Notes:
56194          *  - Only numbered indices are relevant, so arr_idx fast reject is good
56195          *    (this is valid unless there are more than 4**32-1 arguments).
56196          *  - Since variable lookup has no side effects, this can be skipped if
56197          *    DUK_GETDESC_FLAG_PUSH_VALUE is not set.
56198          */
56199
56200         if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
56201                          arr_idx != DUK__NO_ARRAY_INDEX &&
56202                          (flags & DUK_GETDESC_FLAG_PUSH_VALUE))) {
56203                 duk_propdesc temp_desc;
56204
56205                 /* Magically bound variable cannot be an accessor.  However,
56206                  * there may be an accessor property (or a plain property) in
56207                  * place with magic behavior removed.  This happens e.g. when
56208                  * a magic property is redefined with defineProperty().
56209                  * Cannot assert for "not accessor" here.
56210                  */
56211
56212                 /* replaces top of stack with new value if necessary */
56213                 DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0);
56214
56215                 /* This can perform a variable lookup but only into a declarative
56216                  * environment which has no side effects.
56217                  */
56218                 if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
56219                         DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T",
56220                                              (duk_tval *) duk_get_tval(thr, -2),
56221                                              (duk_tval *) duk_get_tval(thr, -1)));
56222                         /* [... old_result result] -> [... result] */
56223                         duk_remove_m2(thr);
56224                 }
56225         }
56226
56227  prop_found_noexotic:
56228         DUK_STATS_INC(thr->heap, stats_getownpropdesc_hit);
56229         return 1;
56230 }
56231
56232 DUK_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) {
56233         DUK_ASSERT(thr != NULL);
56234         DUK_ASSERT(obj != NULL);
56235         DUK_ASSERT(key != NULL);
56236         DUK_ASSERT(out_desc != NULL);
56237         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
56238
56239         return duk__get_own_propdesc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, flags);
56240 }
56241
56242 /*
56243  *  ECMAScript compliant [[GetProperty]](P), for internal use only.
56244  *
56245  *  If property is found:
56246  *    - Fills descriptor fields to 'out_desc'
56247  *    - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
56248  *      property onto the stack ('undefined' for accessor properties).
56249  *    - Returns non-zero
56250  *
56251  *  If property is not found:
56252  *    - 'out_desc' is left in untouched state (possibly garbage)
56253  *    - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
56254  *      set)
56255  *    - Returns zero
56256  *
56257  *  May cause arbitrary side effects and invalidate (most) duk_tval
56258  *  pointers.
56259  */
56260
56261 DUK_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) {
56262         duk_hobject *curr;
56263         duk_uint32_t arr_idx;
56264         duk_uint_t sanity;
56265
56266         DUK_ASSERT(thr != NULL);
56267         DUK_ASSERT(thr->heap != NULL);
56268         DUK_ASSERT(obj != NULL);
56269         DUK_ASSERT(key != NULL);
56270         DUK_ASSERT(out_desc != NULL);
56271         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
56272
56273         DUK_STATS_INC(thr->heap, stats_getpropdesc_count);
56274
56275         arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
56276
56277         DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
56278                              "arr_idx=%ld (obj -> %!O, key -> %!O)",
56279                              (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
56280                              (long) flags, (long) arr_idx,
56281                              (duk_heaphdr *) obj, (duk_heaphdr *) key));
56282
56283         curr = obj;
56284         DUK_ASSERT(curr != NULL);
56285         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
56286         do {
56287                 if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) {
56288                         /* stack contains value (if requested), 'out_desc' is set */
56289                         DUK_STATS_INC(thr->heap, stats_getpropdesc_hit);
56290                         return 1;
56291                 }
56292
56293                 /* not found in 'curr', next in prototype chain; impose max depth */
56294                 if (DUK_UNLIKELY(sanity-- == 0)) {
56295                         if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) {
56296                                 /* treat like property not found */
56297                                 break;
56298                         } else {
56299                                 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
56300                                 DUK_WO_NORETURN(return 0;);
56301                         }
56302                 }
56303                 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
56304         } while (curr != NULL);
56305
56306         /* out_desc is left untouched (possibly garbage), caller must use return
56307          * value to determine whether out_desc can be looked up
56308          */
56309
56310         DUK_STATS_INC(thr->heap, stats_getpropdesc_miss);
56311         return 0;
56312 }
56313
56314 /*
56315  *  Shallow fast path checks for accessing array elements with numeric
56316  *  indices.  The goal is to try to avoid coercing an array index to an
56317  *  (interned) string for the most common lookups, in particular, for
56318  *  standard Array objects.
56319  *
56320  *  Interning is avoided but only for a very narrow set of cases:
56321  *    - Object has array part, index is within array allocation, and
56322  *      value is not unused (= key exists)
56323  *    - Object has no interfering exotic behavior (e.g. arguments or
56324  *      string object exotic behaviors interfere, array exotic
56325  *      behavior does not).
56326  *
56327  *  Current shortcoming: if key does not exist (even if it is within
56328  *  the array allocation range) a slow path lookup with interning is
56329  *  always required.  This can probably be fixed so that there is a
56330  *  quick fast path for non-existent elements as well, at least for
56331  *  standard Array objects.
56332  */
56333
56334 #if defined(DUK_USE_ARRAY_PROP_FASTPATH)
56335 DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
56336         duk_tval *tv;
56337         duk_uint32_t idx;
56338
56339         DUK_UNREF(thr);
56340
56341         if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
56342              !DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
56343              !DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) &&
56344              !DUK_HOBJECT_IS_BUFOBJ(obj) &&
56345              !DUK_HOBJECT_IS_PROXY(obj))) {
56346                 /* Must have array part and no conflicting exotic behaviors.
56347                  * Doesn't need to have array special behavior, e.g. Arguments
56348                  * object has array part.
56349                  */
56350                 return NULL;
56351         }
56352
56353         /* Arrays never have other exotic behaviors. */
56354
56355         DUK_DDD(DUK_DDDPRINT("fast path attempt (no exotic string/arguments/buffer "
56356                              "behavior, object has array part)"));
56357
56358 #if defined(DUK_USE_FASTINT)
56359         if (DUK_TVAL_IS_FASTINT(tv_key)) {
56360                 idx = duk__tval_fastint_to_arr_idx(tv_key);
56361         } else
56362 #endif
56363         if (DUK_TVAL_IS_DOUBLE(tv_key)) {
56364                 idx = duk__tval_number_to_arr_idx(tv_key);
56365         } else {
56366                 DUK_DDD(DUK_DDDPRINT("key is not a number"));
56367                 return NULL;
56368         }
56369
56370         /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
56371          * is 0xffffffffUL.  We don't need to check for that explicitly
56372          * because 0xffffffffUL will never be inside object 'a_size'.
56373          */
56374
56375         if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
56376                 DUK_DDD(DUK_DDDPRINT("key is not an array index or outside array part"));
56377                 return NULL;
56378         }
56379         DUK_ASSERT(idx != 0xffffffffUL);
56380         DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
56381
56382         /* XXX: for array instances we could take a shortcut here and assume
56383          * Array.prototype doesn't contain an array index property.
56384          */
56385
56386         DUK_DDD(DUK_DDDPRINT("key is a valid array index and inside array part"));
56387         tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
56388         if (!DUK_TVAL_IS_UNUSED(tv)) {
56389                 DUK_DDD(DUK_DDDPRINT("-> fast path successful"));
56390                 return tv;
56391         }
56392
56393         DUK_DDD(DUK_DDDPRINT("fast path attempt failed, fall back to slow path"));
56394         return NULL;
56395 }
56396
56397 DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
56398         duk_tval *tv;
56399         duk_harray *a;
56400         duk_uint32_t idx;
56401         duk_uint32_t old_len, new_len;
56402
56403         if (!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) &&
56404               DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
56405               DUK_HOBJECT_HAS_EXTENSIBLE(obj))) {
56406                 return 0;
56407         }
56408         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));  /* caller ensures */
56409
56410         a = (duk_harray *) obj;
56411         DUK_ASSERT_HARRAY_VALID(a);
56412
56413 #if defined(DUK_USE_FASTINT)
56414         if (DUK_TVAL_IS_FASTINT(tv_key)) {
56415                 idx = duk__tval_fastint_to_arr_idx(tv_key);
56416         } else
56417 #endif
56418         if (DUK_TVAL_IS_DOUBLE(tv_key)) {
56419                 idx = duk__tval_number_to_arr_idx(tv_key);
56420         } else {
56421                 DUK_DDD(DUK_DDDPRINT("key is not a number"));
56422                 return 0;
56423         }
56424
56425         /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
56426          * is 0xffffffffUL.  We don't need to check for that explicitly
56427          * because 0xffffffffUL will never be inside object 'a_size'.
56428          */
56429
56430         if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) {  /* for resizing of array part, use slow path */
56431                 return 0;
56432         }
56433         DUK_ASSERT(idx != 0xffffffffUL);
56434         DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
56435
56436         old_len = a->length;
56437
56438         if (idx >= old_len) {
56439                 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
56440                                      "(arr_idx=%ld, old_len=%ld)",
56441                                      (long) idx, (long) old_len));
56442                 if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
56443                         /* The correct behavior here is either a silent error
56444                          * or a TypeError, depending on strictness.  Fall back
56445                          * to the slow path to handle the situation.
56446                          */
56447                         return 0;
56448                 }
56449                 new_len = idx + 1;
56450
56451                 ((duk_harray *) obj)->length = new_len;
56452         }
56453
56454         tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
56455         DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val);  /* side effects */
56456
56457         DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld", (long) idx));
56458         return 1;
56459 }
56460 #endif  /* DUK_USE_ARRAY_PROP_FASTPATH */
56461
56462 /*
56463  *  Fast path for bufobj getprop/putprop
56464  */
56465
56466 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
56467 DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
56468         duk_uint32_t idx;
56469         duk_hbufobj *h_bufobj;
56470         duk_uint_t byte_off;
56471         duk_small_uint_t elem_size;
56472         duk_uint8_t *data;
56473
56474         if (!DUK_HOBJECT_IS_BUFOBJ(obj)) {
56475                 return 0;
56476         }
56477         h_bufobj = (duk_hbufobj *) obj;
56478         if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
56479                 return 0;
56480         }
56481
56482 #if defined(DUK_USE_FASTINT)
56483         if (DUK_TVAL_IS_FASTINT(tv_key)) {
56484                 idx = duk__tval_fastint_to_arr_idx(tv_key);
56485         } else
56486 #endif
56487         if (DUK_TVAL_IS_DOUBLE(tv_key)) {
56488                 idx = duk__tval_number_to_arr_idx(tv_key);
56489         } else {
56490                 return 0;
56491         }
56492
56493         /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
56494          * is 0xffffffffUL.  We don't need to check for that explicitly
56495          * because 0xffffffffUL will never be inside bufobj length.
56496          */
56497
56498         /* Careful with wrapping (left shifting idx would be unsafe). */
56499         if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
56500                 return 0;
56501         }
56502         DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
56503
56504         byte_off = idx << h_bufobj->shift;  /* no wrap assuming h_bufobj->length is valid */
56505         elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
56506
56507         if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
56508                 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
56509                 duk_hbufobj_push_validated_read(thr, h_bufobj, data, elem_size);
56510         } else {
56511                 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
56512                 duk_push_uint(thr, 0);
56513         }
56514
56515         return 1;
56516 }
56517 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
56518
56519 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
56520 DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
56521         duk_uint32_t idx;
56522         duk_hbufobj *h_bufobj;
56523         duk_uint_t byte_off;
56524         duk_small_uint_t elem_size;
56525         duk_uint8_t *data;
56526
56527         if (!(DUK_HOBJECT_IS_BUFOBJ(obj) &&
56528               DUK_TVAL_IS_NUMBER(tv_val))) {
56529                 return 0;
56530         }
56531         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));  /* caller ensures; rom objects are never bufobjs now */
56532
56533         h_bufobj = (duk_hbufobj *) obj;
56534         if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
56535                 return 0;
56536         }
56537
56538 #if defined(DUK_USE_FASTINT)
56539         if (DUK_TVAL_IS_FASTINT(tv_key)) {
56540                 idx = duk__tval_fastint_to_arr_idx(tv_key);
56541         } else
56542 #endif
56543         if (DUK_TVAL_IS_DOUBLE(tv_key)) {
56544                 idx = duk__tval_number_to_arr_idx(tv_key);
56545         } else {
56546                 return 0;
56547         }
56548
56549         /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
56550          * is 0xffffffffUL.  We don't need to check for that explicitly
56551          * because 0xffffffffUL will never be inside bufobj length.
56552          */
56553
56554         /* Careful with wrapping (left shifting idx would be unsafe). */
56555         if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
56556                 return 0;
56557         }
56558         DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
56559
56560         byte_off = idx << h_bufobj->shift;  /* no wrap assuming h_bufobj->length is valid */
56561         elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
56562
56563         /* Value is required to be a number in the fast path so there
56564          * are no side effects in write coercion.
56565          */
56566         duk_push_tval(thr, tv_val);
56567         DUK_ASSERT(duk_is_number(thr, -1));
56568
56569         if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
56570                 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
56571                 duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size);
56572         } else {
56573                 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
56574         }
56575
56576         duk_pop_unsafe(thr);
56577         return 1;
56578 }
56579 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
56580
56581 /*
56582  *  GETPROP: ECMAScript property read.
56583  */
56584
56585 DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
56586         duk_tval tv_obj_copy;
56587         duk_tval tv_key_copy;
56588         duk_hobject *curr = NULL;
56589         duk_hstring *key = NULL;
56590         duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
56591         duk_propdesc desc;
56592         duk_uint_t sanity;
56593
56594         DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
56595                              (void *) thr, (void *) tv_obj, (void *) tv_key,
56596                              (duk_tval *) tv_obj, (duk_tval *) tv_key));
56597
56598         DUK_ASSERT(thr != NULL);
56599         DUK_ASSERT(thr->heap != NULL);
56600         DUK_ASSERT(tv_obj != NULL);
56601         DUK_ASSERT(tv_key != NULL);
56602
56603         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
56604
56605         DUK_STATS_INC(thr->heap, stats_getprop_all);
56606
56607         /*
56608          *  Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
56609          *  them being invalidated by a valstack resize.
56610          *
56611          *  XXX: this is now an overkill for many fast paths.  Rework this
56612          *  to be faster (although switching to a valstack discipline might
56613          *  be a better solution overall).
56614          */
56615
56616         DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
56617         DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
56618         tv_obj = &tv_obj_copy;
56619         tv_key = &tv_key_copy;
56620
56621         /*
56622          *  Coercion and fast path processing
56623          */
56624
56625         switch (DUK_TVAL_GET_TAG(tv_obj)) {
56626         case DUK_TAG_UNDEFINED:
56627         case DUK_TAG_NULL: {
56628                 /* Note: unconditional throw */
56629                 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
56630 #if defined(DUK_USE_PARANOID_ERRORS)
56631                 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
56632 #else
56633                 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
56634                                duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
56635 #endif
56636                 DUK_WO_NORETURN(return 0;);
56637                 break;
56638         }
56639
56640         case DUK_TAG_BOOLEAN: {
56641                 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
56642                 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
56643                 break;
56644         }
56645
56646         case DUK_TAG_STRING: {
56647                 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
56648                 duk_int_t pop_count;
56649
56650                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
56651                         /* Symbols (ES2015 or hidden) don't have virtual properties. */
56652                         DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype"));
56653                         curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE];
56654                         break;
56655                 }
56656
56657 #if defined(DUK_USE_FASTINT)
56658                 if (DUK_TVAL_IS_FASTINT(tv_key)) {
56659                         arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
56660                         DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
56661                         pop_count = 0;
56662                 } else
56663 #endif
56664                 if (DUK_TVAL_IS_NUMBER(tv_key)) {
56665                         arr_idx = duk__tval_number_to_arr_idx(tv_key);
56666                         DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx));
56667                         pop_count = 0;
56668                 } else {
56669                         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
56670                         DUK_ASSERT(key != NULL);
56671                         DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
56672                                              "coercion key is %!T, arr_idx %ld",
56673                                              (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
56674                         pop_count = 1;
56675                 }
56676
56677                 if (arr_idx != DUK__NO_ARRAY_INDEX &&
56678                     arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
56679                         duk_pop_n_unsafe(thr, pop_count);
56680                         duk_push_hstring(thr, h);
56681                         duk_substring(thr, -1, arr_idx, arr_idx + 1);  /* [str] -> [substr] */
56682
56683                         DUK_STATS_INC(thr->heap, stats_getprop_stringidx);
56684                         DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
56685                                              "after coercion -> return char)",
56686                                              (duk_tval *) duk_get_tval(thr, -1)));
56687                         return 1;
56688                 }
56689
56690                 if (pop_count == 0) {
56691                         /* This is a pretty awkward control flow, but we need to recheck the
56692                          * key coercion here.
56693                          */
56694                         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
56695                         DUK_ASSERT(key != NULL);
56696                         DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
56697                                              "coercion key is %!T, arr_idx %ld",
56698                                              (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
56699                 }
56700
56701                 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
56702                         duk_pop_unsafe(thr);  /* [key] -> [] */
56703                         duk_push_uint(thr, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));  /* [] -> [res] */
56704
56705                         DUK_STATS_INC(thr->heap, stats_getprop_stringlen);
56706                         DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
56707                                              "return string length)",
56708                                              (duk_tval *) duk_get_tval(thr, -1)));
56709                         return 1;
56710                 }
56711
56712                 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
56713                 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
56714                 goto lookup;  /* avoid double coercion */
56715         }
56716
56717         case DUK_TAG_OBJECT: {
56718 #if defined(DUK_USE_ARRAY_PROP_FASTPATH)
56719                 duk_tval *tmp;
56720 #endif
56721
56722                 curr = DUK_TVAL_GET_OBJECT(tv_obj);
56723                 DUK_ASSERT(curr != NULL);
56724
56725                 /* XXX: array .length fast path (important in e.g. loops)? */
56726
56727 #if defined(DUK_USE_ARRAY_PROP_FASTPATH)
56728                 tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key);
56729                 if (tmp) {
56730                         duk_push_tval(thr, tmp);
56731
56732                         DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
56733                                              "fast path)",
56734                                              (duk_tval *) duk_get_tval(thr, -1)));
56735                         DUK_STATS_INC(thr->heap, stats_getprop_arrayidx);
56736                         return 1;
56737                 }
56738 #endif
56739
56740 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
56741                 if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) {
56742                         /* Read value pushed on stack. */
56743                         DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufobj "
56744                                              "fast path)",
56745                                              (duk_tval *) duk_get_tval(thr, -1)));
56746                         DUK_STATS_INC(thr->heap, stats_getprop_bufobjidx);
56747                         return 1;
56748                 }
56749 #endif
56750
56751 #if defined(DUK_USE_ES6_PROXY)
56752                 if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(curr))) {
56753                         duk_hobject *h_target;
56754
56755                         if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) {
56756                                 /* -> [ ... trap handler ] */
56757                                 DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key));
56758                                 DUK_STATS_INC(thr->heap, stats_getprop_proxy);
56759                                 duk_push_hobject(thr, h_target);  /* target */
56760                                 duk_push_tval(thr, tv_key);       /* P */
56761                                 duk_push_tval(thr, tv_obj);       /* Receiver: Proxy object */
56762                                 duk_call_method(thr, 3 /*nargs*/);
56763
56764                                 /* Target object must be checked for a conflicting
56765                                  * non-configurable property.
56766                                  */
56767                                 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
56768                                 DUK_ASSERT(key != NULL);
56769
56770                                 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
56771                                         duk_tval *tv_hook = duk_require_tval(thr, -3);  /* value from hook */
56772                                         duk_tval *tv_targ = duk_require_tval(thr, -1);  /* value from target */
56773                                         duk_bool_t datadesc_reject;
56774                                         duk_bool_t accdesc_reject;
56775
56776                                         DUK_DDD(DUK_DDDPRINT("proxy 'get': target has matching property %!O, check for "
56777                                                              "conflicting property; tv_hook=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
56778                                                              "desc.get=%p, desc.set=%p",
56779                                                              (duk_heaphdr *) key, (duk_tval *) tv_hook, (duk_tval *) tv_targ,
56780                                                              (unsigned long) desc.flags,
56781                                                              (void *) desc.get, (void *) desc.set));
56782
56783                                         datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
56784                                                           !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
56785                                                           !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
56786                                                           !duk_js_samevalue(tv_hook, tv_targ);
56787                                         accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
56788                                                          !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
56789                                                          (desc.get == NULL) &&
56790                                                          !DUK_TVAL_IS_UNDEFINED(tv_hook);
56791                                         if (datadesc_reject || accdesc_reject) {
56792                                                 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
56793                                                 DUK_WO_NORETURN(return 0;);
56794                                         }
56795
56796                                         duk_pop_2_unsafe(thr);
56797                                 } else {
56798                                         duk_pop_unsafe(thr);
56799                                 }
56800                                 return 1;  /* return value */
56801                         }
56802
56803                         curr = h_target;  /* resume lookup from target */
56804                         DUK_TVAL_SET_OBJECT(tv_obj, curr);
56805                 }
56806 #endif  /* DUK_USE_ES6_PROXY */
56807
56808                 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) {
56809                         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
56810                         DUK_ASSERT(key != NULL);
56811
56812                         DUK_STATS_INC(thr->heap, stats_getprop_arguments);
56813                         if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
56814                                 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, "
56815                                                      "key matches magically bound property -> skip standard "
56816                                                      "Get with replacement value)",
56817                                                      (duk_tval *) duk_get_tval(thr, -1)));
56818
56819                                 /* no need for 'caller' post-check, because 'key' must be an array index */
56820
56821                                 duk_remove_m2(thr);  /* [key result] -> [result] */
56822                                 return 1;
56823                         }
56824
56825                         goto lookup;  /* avoid double coercion */
56826                 }
56827                 break;
56828         }
56829
56830         /* Buffer has virtual properties similar to string, but indexed values
56831          * are numbers, not 1-byte buffers/strings which would perform badly.
56832          */
56833         case DUK_TAG_BUFFER: {
56834                 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
56835                 duk_int_t pop_count;
56836
56837                 /*
56838                  *  Because buffer values are often looped over, a number fast path
56839                  *  is important.
56840                  */
56841
56842 #if defined(DUK_USE_FASTINT)
56843                 if (DUK_TVAL_IS_FASTINT(tv_key)) {
56844                         arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
56845                         DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
56846                         pop_count = 0;
56847                 }
56848                 else
56849 #endif
56850                 if (DUK_TVAL_IS_NUMBER(tv_key)) {
56851                         arr_idx = duk__tval_number_to_arr_idx(tv_key);
56852                         DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
56853                         pop_count = 0;
56854                 } else {
56855                         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
56856                         DUK_ASSERT(key != NULL);
56857                         DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
56858                                              "coercion key is %!T, arr_idx %ld",
56859                                              (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
56860                         pop_count = 1;
56861                 }
56862
56863                 if (arr_idx != DUK__NO_ARRAY_INDEX &&
56864                     arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
56865                         duk_pop_n_unsafe(thr, pop_count);
56866                         duk_push_uint(thr, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
56867                         DUK_STATS_INC(thr->heap, stats_getprop_bufferidx);
56868                         DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
56869                                              "after coercion -> return byte as number)",
56870                                              (duk_tval *) duk_get_tval(thr, -1)));
56871                         return 1;
56872                 }
56873
56874                 if (pop_count == 0) {
56875                         /* This is a pretty awkward control flow, but we need to recheck the
56876                          * key coercion here.
56877                          */
56878                         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
56879                         DUK_ASSERT(key != NULL);
56880                         DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
56881                                              "coercion key is %!T, arr_idx %ld",
56882                                              (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
56883                 }
56884
56885                 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
56886                         duk_pop_unsafe(thr);  /* [key] -> [] */
56887                         duk_push_uint(thr, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h));  /* [] -> [res] */
56888                         DUK_STATS_INC(thr->heap, stats_getprop_bufferlen);
56889
56890                         DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' "
56891                                              "after coercion -> return buffer length)",
56892                                              (duk_tval *) duk_get_tval(thr, -1)));
56893                         return 1;
56894                 }
56895
56896                 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype"));
56897                 curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
56898                 goto lookup;  /* avoid double coercion */
56899         }
56900
56901         case DUK_TAG_POINTER: {
56902                 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
56903                 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
56904                 break;
56905         }
56906
56907         case DUK_TAG_LIGHTFUNC: {
56908                 /* Lightfuncs inherit getter .name and .length from %NativeFunctionPrototype%. */
56909                 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
56910                 curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
56911                 break;
56912         }
56913
56914 #if defined(DUK_USE_FASTINT)
56915         case DUK_TAG_FASTINT:
56916 #endif
56917         default: {
56918                 /* number */
56919                 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
56920                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_obj));
56921                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
56922                 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
56923                 break;
56924         }
56925         }
56926
56927         /* key coercion (unless already coerced above) */
56928         DUK_ASSERT(key == NULL);
56929         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
56930         DUK_ASSERT(key != NULL);
56931         /*
56932          *  Property lookup
56933          */
56934
56935  lookup:
56936         /* [key] (coerced) */
56937         DUK_ASSERT(curr != NULL);
56938         DUK_ASSERT(key != NULL);
56939
56940         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
56941         do {
56942                 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
56943                         goto next_in_chain;
56944                 }
56945
56946                 if (desc.get != NULL) {
56947                         /* accessor with defined getter */
56948                         DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
56949
56950                         duk_pop_unsafe(thr);              /* [key undefined] -> [key] */
56951                         duk_push_hobject(thr, desc.get);
56952                         duk_push_tval(thr, tv_obj);       /* note: original, uncoerced base */
56953 #if defined(DUK_USE_NONSTD_GETTER_KEY_ARGUMENT)
56954                         duk_dup_m3(thr);
56955                         duk_call_method(thr, 1);          /* [key getter this key] -> [key retval] */
56956 #else
56957                         duk_call_method(thr, 0);          /* [key getter this] -> [key retval] */
56958 #endif
56959                 } else {
56960                         /* [key value] or [key undefined] */
56961
56962                         /* data property or accessor without getter */
56963                         DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
56964                                    (desc.get == NULL));
56965
56966                         /* if accessor without getter, return value is undefined */
56967                         DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
56968                                    duk_is_undefined(thr, -1));
56969
56970                         /* Note: for an accessor without getter, falling through to
56971                          * check for "caller" exotic behavior is unnecessary as
56972                          * "undefined" will never activate the behavior.  But it does
56973                          * no harm, so we'll do it anyway.
56974                          */
56975                 }
56976
56977                 goto found;  /* [key result] */
56978
56979          next_in_chain:
56980                 /* XXX: option to pretend property doesn't exist if sanity limit is
56981                  * hit might be useful.
56982                  */
56983                 if (DUK_UNLIKELY(sanity-- == 0)) {
56984                         DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
56985                         DUK_WO_NORETURN(return 0;);
56986                 }
56987                 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
56988         } while (curr != NULL);
56989
56990         /*
56991          *  Not found
56992          */
56993
56994         duk_to_undefined(thr, -1);  /* [key] -> [undefined] (default value) */
56995
56996         DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(thr, -1)));
56997         return 0;
56998
56999         /*
57000          *  Found; post-processing (Function and arguments objects)
57001          */
57002
57003  found:
57004         /* [key result] */
57005
57006 #if !defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57007         /* Special behavior for 'caller' property of (non-bound) function objects
57008          * and non-strict Arguments objects: if 'caller' -value- (!) is a strict
57009          * mode function, throw a TypeError (E5 Sections 15.3.5.4, 10.6).
57010          * Quite interestingly, a non-strict function with no formal arguments
57011          * will get an arguments object -without- special 'caller' behavior!
57012          *
57013          * The E5.1 spec is a bit ambiguous if this special behavior applies when
57014          * a bound function is the base value (not the 'caller' value): Section
57015          * 15.3.4.5 (describing bind()) states that [[Get]] for bound functions
57016          * matches that of Section 15.3.5.4 ([[Get]] for Function instances).
57017          * However, Section 13.3.5.4 has "NOTE: Function objects created using
57018          * Function.prototype.bind use the default [[Get]] internal method."
57019          * The current implementation assumes this means that bound functions
57020          * should not have the special [[Get]] behavior.
57021          *
57022          * The E5.1 spec is also a bit unclear if the TypeError throwing is
57023          * applied if the 'caller' value is a strict bound function.  The
57024          * current implementation will throw even for both strict non-bound
57025          * and strict bound functions.
57026          *
57027          * See test-dev-strict-func-as-caller-prop-value.js for quite extensive
57028          * tests.
57029          *
57030          * This exotic behavior is disabled when the non-standard 'caller' property
57031          * is enabled, as it conflicts with the free use of 'caller'.
57032          */
57033         if (key == DUK_HTHREAD_STRING_CALLER(thr) &&
57034             DUK_TVAL_IS_OBJECT(tv_obj)) {
57035                 duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj);
57036                 DUK_ASSERT(orig != NULL);
57037
57038                 if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) ||
57039                     DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
57040                         duk_hobject *h;
57041
57042                         /* XXX: The TypeError is currently not applied to bound
57043                          * functions because the 'strict' flag is not copied by
57044                          * bind().  This may or may not be correct, the specification
57045                          * only refers to the value being a "strict mode Function
57046                          * object" which is ambiguous.
57047                          */
57048                         DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(orig));
57049
57050                         h = duk_get_hobject(thr, -1);  /* NULL if not an object */
57051                         if (h &&
57052                             DUK_HOBJECT_IS_FUNCTION(h) &&
57053                             DUK_HOBJECT_HAS_STRICT(h)) {
57054                                 /* XXX: sufficient to check 'strict', assert for 'is function' */
57055                                 DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ);
57056                                 DUK_WO_NORETURN(return 0;);
57057                         }
57058                 }
57059         }
57060 #endif   /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
57061
57062         duk_remove_m2(thr);  /* [key result] -> [result] */
57063
57064         DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(thr, -1)));
57065         return 1;
57066 }
57067
57068 /*
57069  *  HASPROP: ECMAScript property existence check ("in" operator).
57070  *
57071  *  Interestingly, the 'in' operator does not do any coercion of
57072  *  the target object.
57073  */
57074
57075 DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
57076         duk_tval tv_key_copy;
57077         duk_hobject *obj;
57078         duk_hstring *key;
57079         duk_uint32_t arr_idx;
57080         duk_bool_t rc;
57081         duk_propdesc desc;
57082
57083         DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
57084                              (void *) thr, (void *) tv_obj, (void *) tv_key,
57085                              (duk_tval *) tv_obj, (duk_tval *) tv_key));
57086
57087         DUK_ASSERT(thr != NULL);
57088         DUK_ASSERT(thr->heap != NULL);
57089         DUK_ASSERT(tv_obj != NULL);
57090         DUK_ASSERT(tv_key != NULL);
57091         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
57092
57093         DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
57094         tv_key = &tv_key_copy;
57095
57096         /*
57097          *  The 'in' operator requires an object as its right hand side,
57098          *  throwing a TypeError unconditionally if this is not the case.
57099          *
57100          *  However, lightfuncs need to behave like fully fledged objects
57101          *  here to be maximally transparent, so we need to handle them
57102          *  here.  Same goes for plain buffers which behave like ArrayBuffers.
57103          */
57104
57105         /* XXX: Refactor key coercion so that it's only called once.  It can't
57106          * be trivially lifted here because the object must be type checked
57107          * first.
57108          */
57109
57110         if (DUK_TVAL_IS_OBJECT(tv_obj)) {
57111                 obj = DUK_TVAL_GET_OBJECT(tv_obj);
57112                 DUK_ASSERT(obj != NULL);
57113
57114                 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
57115         } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
57116                 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
57117                 if (duk__key_is_plain_buf_ownprop(thr, DUK_TVAL_GET_BUFFER(tv_obj), key, arr_idx)) {
57118                         rc = 1;
57119                         goto pop_and_return;
57120                 }
57121                 obj = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
57122         } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
57123                 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
57124
57125                 /* If not found, resume existence check from %NativeFunctionPrototype%.
57126                  * We can just substitute the value in this case; nothing will
57127                  * need the original base value (as would be the case with e.g.
57128                  * setters/getters.
57129                  */
57130                 obj = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
57131         } else {
57132                 /* Note: unconditional throw */
57133                 DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
57134                 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
57135                 DUK_WO_NORETURN(return 0;);
57136         }
57137
57138         /* XXX: fast path for arrays? */
57139
57140         DUK_ASSERT(key != NULL);
57141         DUK_ASSERT(obj != NULL);
57142         DUK_UNREF(arr_idx);
57143
57144 #if defined(DUK_USE_ES6_PROXY)
57145         if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
57146                 duk_hobject *h_target;
57147                 duk_bool_t tmp_bool;
57148
57149                 /* XXX: the key in 'key in obj' is string coerced before we're called
57150                  * (which is the required behavior in E5/E5.1/E6) so the key is a string
57151                  * here already.
57152                  */
57153
57154                 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) {
57155                         /* [ ... key trap handler ] */
57156                         DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key));
57157                         duk_push_hobject(thr, h_target);  /* target */
57158                         duk_push_tval(thr, tv_key);       /* P */
57159                         duk_call_method(thr, 2 /*nargs*/);
57160                         tmp_bool = duk_to_boolean_top_pop(thr);
57161                         if (!tmp_bool) {
57162                                 /* Target object must be checked for a conflicting
57163                                  * non-configurable property.
57164                                  */
57165
57166                                 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) {  /* don't push value */
57167                                         DUK_DDD(DUK_DDDPRINT("proxy 'has': target has matching property %!O, check for "
57168                                                              "conflicting property; desc.flags=0x%08lx, "
57169                                                              "desc.get=%p, desc.set=%p",
57170                                                              (duk_heaphdr *) key, (unsigned long) desc.flags,
57171                                                              (void *) desc.get, (void *) desc.set));
57172                                         /* XXX: Extensibility check for target uses IsExtensible().  If we
57173                                          * implemented the isExtensible trap and didn't reject proxies as
57174                                          * proxy targets, it should be respected here.
57175                                          */
57176                                         if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&  /* property is configurable and */
57177                                               DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) {          /* ... target is extensible */
57178                                                 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
57179                                                 DUK_WO_NORETURN(return 0;);
57180                                         }
57181                                 }
57182                         }
57183
57184                         duk_pop_unsafe(thr);  /* [ key ] -> [] */
57185                         return tmp_bool;
57186                 }
57187
57188                 obj = h_target;  /* resume check from proxy target */
57189         }
57190 #endif  /* DUK_USE_ES6_PROXY */
57191
57192         /* XXX: inline into a prototype walking loop? */
57193
57194         rc = duk__get_propdesc(thr, obj, key, &desc, 0 /*flags*/);  /* don't push value */
57195         /* fall through */
57196
57197  pop_and_return:
57198         duk_pop_unsafe(thr);  /* [ key ] -> [] */
57199         return rc;
57200 }
57201
57202 /*
57203  *  HASPROP variant used internally.
57204  *
57205  *  This primitive must never throw an error, callers rely on this.
57206  *  In particular, don't throw an error for prototype loops; instead,
57207  *  pretend like the property doesn't exist if a prototype sanity limit
57208  *  is reached.
57209  *
57210  *  Does not implement proxy behavior: if applied to a proxy object,
57211  *  returns key existence on the proxy object itself.
57212  */
57213
57214 DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
57215         duk_propdesc dummy;
57216
57217         DUK_ASSERT(thr != NULL);
57218         DUK_ASSERT(thr->heap != NULL);
57219         DUK_ASSERT(obj != NULL);
57220         DUK_ASSERT(key != NULL);
57221
57222         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
57223
57224         return duk__get_propdesc(thr, obj, key, &dummy, DUK_GETDESC_FLAG_IGNORE_PROTOLOOP);  /* don't push value */
57225 }
57226
57227 /*
57228  *  Helper: handle Array object 'length' write which automatically
57229  *  deletes properties, see E5 Section 15.4.5.1, step 3.  This is
57230  *  quite tricky to get right.
57231  *
57232  *  Used by duk_hobject_putprop().
57233  */
57234
57235 /* Coerce a new .length candidate to a number and check that it's a valid
57236  * .length.
57237  */
57238 DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tval *tv) {
57239         duk_uint32_t res;
57240         duk_double_t d;
57241
57242 #if !defined(DUK_USE_PREFER_SIZE)
57243 #if defined(DUK_USE_FASTINT)
57244         /* When fastints are enabled, the most interesting case is assigning
57245          * a fastint to .length (e.g. arr.length = 0).
57246          */
57247         if (DUK_TVAL_IS_FASTINT(tv)) {
57248                 /* Very common case. */
57249                 duk_int64_t fi;
57250                 fi = DUK_TVAL_GET_FASTINT(tv);
57251                 if (fi < 0 || fi > DUK_I64_CONSTANT(0xffffffff)) {
57252                         goto fail_range;
57253                 }
57254                 return (duk_uint32_t) fi;
57255         }
57256 #else  /* DUK_USE_FASTINT */
57257         /* When fastints are not enabled, the most interesting case is any
57258          * number.
57259          */
57260         if (DUK_TVAL_IS_DOUBLE(tv)) {
57261                 d = DUK_TVAL_GET_NUMBER(tv);
57262         }
57263 #endif  /* DUK_USE_FASTINT */
57264         else
57265 #endif  /* !DUK_USE_PREFER_SIZE */
57266         {
57267                 /* In all other cases, and when doing a size optimized build,
57268                  * fall back to the comprehensive handler.
57269                  */
57270                 d = duk_js_tonumber(thr, tv);
57271         }
57272
57273         /* Refuse to update an Array's 'length' to a value outside the
57274          * 32-bit range.  Negative zero is accepted as zero.
57275          */
57276         res = duk_double_to_uint32_t(d);
57277         if ((duk_double_t) res != d) {
57278                 goto fail_range;
57279         }
57280
57281         return res;
57282
57283  fail_range:
57284         DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
57285         DUK_WO_NORETURN(return 0;);
57286 }
57287
57288 /* Delete elements required by a smaller length, taking into account
57289  * potentially non-configurable elements.  Returns non-zero if all
57290  * elements could be deleted, and zero if all or some elements could
57291  * not be deleted.  Also writes final "target length" to 'out_result_len'.
57292  * This is the length value that should go into the 'length' property
57293  * (must be set by the caller).  Never throws an error.
57294  */
57295 DUK_LOCAL
57296 duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
57297                                                 duk_hobject *obj,
57298                                                 duk_uint32_t old_len,
57299                                                 duk_uint32_t new_len,
57300                                                 duk_bool_t force_flag,
57301                                                 duk_uint32_t *out_result_len) {
57302         duk_uint32_t target_len;
57303         duk_uint_fast32_t i;
57304         duk_uint32_t arr_idx;
57305         duk_hstring *key;
57306         duk_tval *tv;
57307         duk_bool_t rc;
57308
57309         DUK_DDD(DUK_DDDPRINT("new array length smaller than old (%ld -> %ld), "
57310                              "probably need to remove elements",
57311                              (long) old_len, (long) new_len));
57312
57313         /*
57314          *  New length is smaller than old length, need to delete properties above
57315          *  the new length.
57316          *
57317          *  If array part exists, this is straightforward: array entries cannot
57318          *  be non-configurable so this is guaranteed to work.
57319          *
57320          *  If array part does not exist, array-indexed values are scattered
57321          *  in the entry part, and some may not be configurable (preventing length
57322          *  from becoming lower than their index + 1).  To handle the algorithm
57323          *  in E5 Section 15.4.5.1, step l correctly, we scan the entire property
57324          *  set twice.
57325          */
57326
57327         DUK_ASSERT(thr != NULL);
57328         DUK_ASSERT(obj != NULL);
57329         DUK_ASSERT(new_len < old_len);
57330         DUK_ASSERT(out_result_len != NULL);
57331         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
57332
57333         DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));
57334         DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj));
57335
57336         if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
57337                 /*
57338                  *  All defined array-indexed properties are in the array part
57339                  *  (we assume the array part is comprehensive), and all array
57340                  *  entries are writable, configurable, and enumerable.  Thus,
57341                  *  nothing can prevent array entries from being deleted.
57342                  */
57343
57344                 DUK_DDD(DUK_DDDPRINT("have array part, easy case"));
57345
57346                 if (old_len < DUK_HOBJECT_GET_ASIZE(obj)) {
57347                         /* XXX: assertion that entries >= old_len are already unused */
57348                         i = old_len;
57349                 } else {
57350                         i = DUK_HOBJECT_GET_ASIZE(obj);
57351                 }
57352                 DUK_ASSERT(i <= DUK_HOBJECT_GET_ASIZE(obj));
57353
57354                 while (i > new_len) {
57355                         i--;
57356                         tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
57357                         DUK_TVAL_SET_UNUSED_UPDREF(thr, tv);  /* side effects */
57358                 }
57359
57360                 *out_result_len = new_len;
57361                 return 1;
57362         } else {
57363                 /*
57364                  *  Entries part is a bit more complex.
57365                  */
57366
57367                 /* Stage 1: find highest preventing non-configurable entry (if any).
57368                  * When forcing, ignore non-configurability.
57369                  */
57370
57371                 DUK_DDD(DUK_DDDPRINT("no array part, slow case"));
57372
57373                 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 1: find target_len "
57374                                      "(highest preventing non-configurable entry (if any))"));
57375
57376                 target_len = new_len;
57377                 if (force_flag) {
57378                         DUK_DDD(DUK_DDDPRINT("array length write, no array part; force flag -> skip stage 1"));
57379                         goto skip_stage1;
57380                 }
57381                 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
57382                         key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
57383                         if (!key) {
57384                                 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
57385                                 continue;
57386                         }
57387                         if (!DUK_HSTRING_HAS_ARRIDX(key)) {
57388                                 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
57389                                 continue;
57390                         }
57391
57392                         DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key));  /* XXX: macro checks for array index flag, which is unnecessary here */
57393                         arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
57394                         DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
57395                         DUK_ASSERT(arr_idx < old_len);  /* consistency requires this */
57396
57397                         if (arr_idx < new_len) {
57398                                 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below new_len",
57399                                                      (long) i, (long) arr_idx));
57400                                 continue;
57401                         }
57402                         if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)) {
57403                                 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is a relevant array index %ld, but configurable",
57404                                                      (long) i, (long) arr_idx));
57405                                 continue;
57406                         }
57407
57408                         /* relevant array index is non-configurable, blocks write */
57409                         if (arr_idx >= target_len) {
57410                                 DUK_DDD(DUK_DDDPRINT("entry at index %ld has arr_idx %ld, is not configurable, "
57411                                                      "update target_len %ld -> %ld",
57412                                                      (long) i, (long) arr_idx, (long) target_len,
57413                                                      (long) (arr_idx + 1)));
57414                                 target_len = arr_idx + 1;
57415                         }
57416                 }
57417          skip_stage1:
57418
57419                 /* stage 2: delete configurable entries above target length */
57420
57421                 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld, target_len=%ld",
57422                                      (long) old_len, (long) new_len, (long) target_len));
57423
57424                 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 2: remove "
57425                                      "entries >= target_len"));
57426
57427                 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
57428                         key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
57429                         if (!key) {
57430                                 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
57431                                 continue;
57432                         }
57433                         if (!DUK_HSTRING_HAS_ARRIDX(key)) {
57434                                 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
57435                                 continue;
57436                         }
57437
57438                         DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key));  /* XXX: macro checks for array index flag, which is unnecessary here */
57439                         arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
57440                         DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
57441                         DUK_ASSERT(arr_idx < old_len);  /* consistency requires this */
57442
57443                         if (arr_idx < target_len) {
57444                                 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below target_len",
57445                                                      (long) i, (long) arr_idx));
57446                                 continue;
57447                         }
57448                         DUK_ASSERT(force_flag || DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i));  /* stage 1 guarantees */
57449
57450                         DUK_DDD(DUK_DDDPRINT("delete entry index %ld: key is array index %ld",
57451                                              (long) i, (long) arr_idx));
57452
57453                         /*
57454                          *  Slow delete, but we don't care as we're already in a very slow path.
57455                          *  The delete always succeeds: key has no exotic behavior, property
57456                          *  is configurable, and no resize occurs.
57457                          */
57458                         rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0);
57459                         DUK_UNREF(rc);
57460                         DUK_ASSERT(rc != 0);
57461                 }
57462
57463                 /* stage 3: update length (done by caller), decide return code */
57464
57465                 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)"));
57466
57467                 *out_result_len = target_len;
57468
57469                 if (target_len == new_len) {
57470                         DUK_DDD(DUK_DDDPRINT("target_len matches new_len, return success"));
57471                         return 1;
57472                 }
57473                 DUK_DDD(DUK_DDDPRINT("target_len does not match new_len (some entry prevented "
57474                                      "full length adjustment), return error"));
57475                 return 0;
57476         }
57477
57478         DUK_UNREACHABLE();
57479 }
57480
57481 /* XXX: is valstack top best place for argument? */
57482 DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
57483         duk_harray *a;
57484         duk_uint32_t old_len;
57485         duk_uint32_t new_len;
57486         duk_uint32_t result_len;
57487         duk_bool_t rc;
57488
57489         DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, "
57490                              "new val: %!T",
57491                              (duk_tval *) duk_get_tval(thr, -1)));
57492
57493         DUK_ASSERT(thr != NULL);
57494         DUK_ASSERT(obj != NULL);
57495
57496         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
57497
57498         DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));
57499         DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj));
57500         a = (duk_harray *) obj;
57501         DUK_ASSERT_HARRAY_VALID(a);
57502
57503         DUK_ASSERT(duk_is_valid_index(thr, -1));
57504
57505         /*
57506          *  Get old and new length
57507          */
57508
57509         old_len = a->length;
57510         new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1));
57511         DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
57512
57513         /*
57514          *  Writability check
57515          */
57516
57517         if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
57518                 DUK_DDD(DUK_DDDPRINT("length is not writable, fail"));
57519                 return 0;
57520         }
57521
57522         /*
57523          *  New length not lower than old length => no changes needed
57524          *  (not even array allocation).
57525          */
57526
57527         if (new_len >= old_len) {
57528                 DUK_DDD(DUK_DDDPRINT("new length is same or higher than old length, just update length, no deletions"));
57529                 a->length = new_len;
57530                 return 1;
57531         }
57532
57533         DUK_DDD(DUK_DDDPRINT("new length is lower than old length, probably must delete entries"));
57534
57535         /*
57536          *  New length lower than old length => delete elements, then
57537          *  update length.
57538          *
57539          *  Note: even though a bunch of elements have been deleted, the 'desc' is
57540          *  still valid as properties haven't been resized (and entries compacted).
57541          */
57542
57543         rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len);
57544         DUK_ASSERT(result_len >= new_len && result_len <= old_len);
57545
57546         a->length = result_len;
57547
57548         /* XXX: shrink array allocation or entries compaction here? */
57549
57550         return rc;
57551 }
57552
57553 /*
57554  *  PUTPROP: ECMAScript property write.
57555  *
57556  *  Unlike ECMAScript primitive which returns nothing, returns 1 to indicate
57557  *  success and 0 to indicate failure (assuming throw is not set).
57558  *
57559  *  This is an extremely tricky function.  Some examples:
57560  *
57561  *    * Currently a decref may trigger a GC, which may compact an object's
57562  *      property allocation.  Consequently, any entry indices (e_idx) will
57563  *      be potentially invalidated by a decref.
57564  *
57565  *    * Exotic behaviors (strings, arrays, arguments object) require,
57566  *      among other things:
57567  *
57568  *      - Preprocessing before and postprocessing after an actual property
57569  *        write.  For example, array index write requires pre-checking the
57570  *        array 'length' property for access control, and may require an
57571  *        array 'length' update after the actual write has succeeded (but
57572  *        not if it fails).
57573  *
57574  *      - Deletion of multiple entries, as a result of array 'length' write.
57575  *
57576  *    * Input values are taken as pointers which may point to the valstack.
57577  *      If valstack is resized because of the put (this may happen at least
57578  *      when the array part is abandoned), the pointers can be invalidated.
57579  *      (We currently make a copy of all of the input values to avoid issues.)
57580  */
57581
57582 DUK_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) {
57583         duk_tval tv_obj_copy;
57584         duk_tval tv_key_copy;
57585         duk_tval tv_val_copy;
57586         duk_hobject *orig = NULL;  /* NULL if tv_obj is primitive */
57587         duk_hobject *curr;
57588         duk_hstring *key = NULL;
57589         duk_propdesc desc;
57590         duk_tval *tv;
57591         duk_uint32_t arr_idx;
57592         duk_bool_t rc;
57593         duk_int_t e_idx;
57594         duk_uint_t sanity;
57595         duk_uint32_t new_array_length = 0;  /* 0 = no update */
57596
57597         DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld "
57598                              "(obj -> %!T, key -> %!T, val -> %!T)",
57599                              (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val,
57600                              (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val));
57601
57602         DUK_ASSERT(thr != NULL);
57603         DUK_ASSERT(thr->heap != NULL);
57604         DUK_ASSERT(tv_obj != NULL);
57605         DUK_ASSERT(tv_key != NULL);
57606         DUK_ASSERT(tv_val != NULL);
57607
57608         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
57609
57610         DUK_STATS_INC(thr->heap, stats_putprop_all);
57611
57612         /*
57613          *  Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
57614          *  them being invalidated by a valstack resize.
57615          *
57616          *  XXX: this is an overkill for some paths, so optimize this later
57617          *  (or maybe switch to a stack arguments model entirely).
57618          */
57619
57620         DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
57621         DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
57622         DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val);
57623         tv_obj = &tv_obj_copy;
57624         tv_key = &tv_key_copy;
57625         tv_val = &tv_val_copy;
57626
57627         /*
57628          *  Coercion and fast path processing.
57629          */
57630
57631         switch (DUK_TVAL_GET_TAG(tv_obj)) {
57632         case DUK_TAG_UNDEFINED:
57633         case DUK_TAG_NULL: {
57634                 /* Note: unconditional throw */
57635                 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)",
57636                                      (duk_tval *) tv_obj));
57637 #if defined(DUK_USE_PARANOID_ERRORS)
57638                 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
57639 #else
57640                 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
57641                                duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
57642 #endif
57643                 DUK_WO_NORETURN(return 0;);
57644                 break;
57645         }
57646
57647         case DUK_TAG_BOOLEAN: {
57648                 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
57649                 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
57650                 break;
57651         }
57652
57653         case DUK_TAG_STRING: {
57654                 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
57655
57656                 /*
57657                  *  Note: currently no fast path for array index writes.
57658                  *  They won't be possible anyway as strings are immutable.
57659                  */
57660
57661                 DUK_ASSERT(key == NULL);
57662                 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
57663                 DUK_ASSERT(key != NULL);
57664
57665                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
57666                         /* Symbols (ES2015 or hidden) don't have virtual properties. */
57667                         curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE];
57668                         goto lookup;
57669                 }
57670
57671                 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
57672                         goto fail_not_writable;
57673                 }
57674
57675                 if (arr_idx != DUK__NO_ARRAY_INDEX &&
57676                     arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
57677                         goto fail_not_writable;
57678                 }
57679
57680                 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
57681                 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
57682                 goto lookup;  /* avoid double coercion */
57683         }
57684
57685         case DUK_TAG_OBJECT: {
57686                 orig = DUK_TVAL_GET_OBJECT(tv_obj);
57687                 DUK_ASSERT(orig != NULL);
57688
57689 #if defined(DUK_USE_ROM_OBJECTS)
57690                 /* With this check in place fast paths won't need read-only
57691                  * object checks.  This is technically incorrect if there are
57692                  * setters that cause no writes to ROM objects, but current
57693                  * built-ins don't have such setters.
57694                  */
57695                 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
57696                         DUK_DD(DUK_DDPRINT("attempt to putprop on read-only target object"));
57697                         goto fail_not_writable_no_pop;  /* Must avoid duk_pop() in exit path */
57698                 }
57699 #endif
57700
57701                 /* The fast path for array property put is not fully compliant:
57702                  * If one places conflicting number-indexed properties into
57703                  * Array.prototype (for example, a non-writable Array.prototype[7])
57704                  * the fast path will incorrectly ignore them.
57705                  *
57706                  * This fast path could be made compliant by falling through
57707                  * to the slow path if the previous value was UNUSED.  This would
57708                  * also remove the need to check for extensibility.  Right now a
57709                  * non-extensible array is slower than an extensible one as far
57710                  * as writes are concerned.
57711                  *
57712                  * The fast path behavior is documented in more detail here:
57713                  * tests/ecmascript/test-misc-array-fast-write.js
57714                  */
57715
57716                 /* XXX: array .length? */
57717
57718 #if defined(DUK_USE_ARRAY_PROP_FASTPATH)
57719                 if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val) != 0) {
57720                         DUK_DDD(DUK_DDDPRINT("array fast path success"));
57721                         DUK_STATS_INC(thr->heap, stats_putprop_arrayidx);
57722                         return 1;
57723                 }
57724 #endif
57725
57726 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
57727                 if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) {
57728                         DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufobj fast path"));
57729                         DUK_STATS_INC(thr->heap, stats_putprop_bufobjidx);
57730                         return 1;
57731                 }
57732 #endif
57733
57734 #if defined(DUK_USE_ES6_PROXY)
57735                 if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(orig))) {
57736                         duk_hobject *h_target;
57737                         duk_bool_t tmp_bool;
57738
57739                         if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) {
57740                                 /* -> [ ... trap handler ] */
57741                                 DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key));
57742                                 DUK_STATS_INC(thr->heap, stats_putprop_proxy);
57743                                 duk_push_hobject(thr, h_target);  /* target */
57744                                 duk_push_tval(thr, tv_key);       /* P */
57745                                 duk_push_tval(thr, tv_val);       /* V */
57746                                 duk_push_tval(thr, tv_obj);       /* Receiver: Proxy object */
57747                                 duk_call_method(thr, 4 /*nargs*/);
57748                                 tmp_bool = duk_to_boolean_top_pop(thr);
57749                                 if (!tmp_bool) {
57750                                         goto fail_proxy_rejected;
57751                                 }
57752
57753                                 /* Target object must be checked for a conflicting
57754                                  * non-configurable property.
57755                                  */
57756                                 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
57757                                 DUK_ASSERT(key != NULL);
57758
57759                                 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
57760                                         duk_tval *tv_targ = duk_require_tval(thr, -1);
57761                                         duk_bool_t datadesc_reject;
57762                                         duk_bool_t accdesc_reject;
57763
57764                                         DUK_DDD(DUK_DDDPRINT("proxy 'set': target has matching property %!O, check for "
57765                                                              "conflicting property; tv_val=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
57766                                                              "desc.get=%p, desc.set=%p",
57767                                                              (duk_heaphdr *) key, (duk_tval *) tv_val, (duk_tval *) tv_targ,
57768                                                              (unsigned long) desc.flags,
57769                                                              (void *) desc.get, (void *) desc.set));
57770
57771                                         datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
57772                                                           !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
57773                                                           !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
57774                                                           !duk_js_samevalue(tv_val, tv_targ);
57775                                         accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
57776                                                          !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
57777                                                          (desc.set == NULL);
57778                                         if (datadesc_reject || accdesc_reject) {
57779                                                 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
57780                                                 DUK_WO_NORETURN(return 0;);
57781                                         }
57782
57783                                         duk_pop_2_unsafe(thr);
57784                                 } else {
57785                                         duk_pop_unsafe(thr);
57786                                 }
57787                                 return 1;  /* success */
57788                         }
57789
57790                         orig = h_target;  /* resume write to target */
57791                         DUK_TVAL_SET_OBJECT(tv_obj, orig);
57792                 }
57793 #endif  /* DUK_USE_ES6_PROXY */
57794
57795                 curr = orig;
57796                 break;
57797         }
57798
57799         case DUK_TAG_BUFFER: {
57800                 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
57801                 duk_int_t pop_count = 0;
57802
57803                 /*
57804                  *  Because buffer values may be looped over and read/written
57805                  *  from, an array index fast path is important.
57806                  */
57807
57808 #if defined(DUK_USE_FASTINT)
57809                 if (DUK_TVAL_IS_FASTINT(tv_key)) {
57810                         arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
57811                         DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
57812                         pop_count = 0;
57813                 } else
57814 #endif
57815                 if (DUK_TVAL_IS_NUMBER(tv_key)) {
57816                         arr_idx = duk__tval_number_to_arr_idx(tv_key);
57817                         DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
57818                         pop_count = 0;
57819                 } else {
57820                         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
57821                         DUK_ASSERT(key != NULL);
57822                         DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
57823                                              "coercion key is %!T, arr_idx %ld",
57824                                              (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
57825                         pop_count = 1;
57826                 }
57827
57828                 if (arr_idx != DUK__NO_ARRAY_INDEX &&
57829                     arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
57830                         duk_uint8_t *data;
57831                         DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
57832                         data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
57833
57834                         /* XXX: duk_to_int() ensures we'll get 8 lowest bits as
57835                          * as input is within duk_int_t range (capped outside it).
57836                          */
57837 #if defined(DUK_USE_FASTINT)
57838                         /* Buffer writes are often integers. */
57839                         if (DUK_TVAL_IS_FASTINT(tv_val)) {
57840                                 data[arr_idx] = (duk_uint8_t) DUK_TVAL_GET_FASTINT_U32(tv_val);
57841                         }
57842                         else
57843 #endif
57844                         {
57845                                 duk_push_tval(thr, tv_val);
57846                                 data[arr_idx] = (duk_uint8_t) duk_to_uint32(thr, -1);
57847                                 pop_count++;
57848                         }
57849
57850                         duk_pop_n_unsafe(thr, pop_count);
57851                         DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)"));
57852                         DUK_STATS_INC(thr->heap, stats_putprop_bufferidx);
57853                         return 1;
57854                 }
57855
57856                 if (pop_count == 0) {
57857                         /* This is a pretty awkward control flow, but we need to recheck the
57858                          * key coercion here.
57859                          */
57860                         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
57861                         DUK_ASSERT(key != NULL);
57862                         DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
57863                                              "coercion key is %!T, arr_idx %ld",
57864                                              (duk_tval *) duk_get_tval(thr, -1), (long) arr_idx));
57865                 }
57866
57867                 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
57868                         goto fail_not_writable;
57869                 }
57870
57871                 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype"));
57872                 curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
57873                 goto lookup;  /* avoid double coercion */
57874         }
57875
57876         case DUK_TAG_POINTER: {
57877                 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
57878                 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
57879                 break;
57880         }
57881
57882         case DUK_TAG_LIGHTFUNC: {
57883                 /* Lightfuncs have no own properties and are considered non-extensible.
57884                  * However, the write may be captured by an inherited setter which
57885                  * means we can't stop the lookup here.
57886                  */
57887                 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
57888                 curr = thr->builtins[DUK_BIDX_NATIVE_FUNCTION_PROTOTYPE];
57889                 break;
57890         }
57891
57892 #if defined(DUK_USE_FASTINT)
57893         case DUK_TAG_FASTINT:
57894 #endif
57895         default: {
57896                 /* number */
57897                 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
57898                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
57899                 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
57900                 break;
57901         }
57902         }
57903
57904         DUK_ASSERT(key == NULL);
57905         arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
57906         DUK_ASSERT(key != NULL);
57907
57908  lookup:
57909
57910         /*
57911          *  Check whether the property already exists in the prototype chain.
57912          *  Note that the actual write goes into the original base object
57913          *  (except if an accessor property captures the write).
57914          */
57915
57916         /* [key] */
57917
57918         DUK_ASSERT(curr != NULL);
57919         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
57920         do {
57921                 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, 0 /*flags*/)) {  /* don't push value */
57922                         goto next_in_chain;
57923                 }
57924
57925                 if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
57926                         /*
57927                          *  Found existing accessor property (own or inherited).
57928                          *  Call setter with 'this' set to orig, and value as the only argument.
57929                          *  Setter calls are OK even for ROM objects.
57930                          *
57931                          *  Note: no exotic arguments object behavior, because [[Put]] never
57932                          *  calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b).
57933                          */
57934
57935                         duk_hobject *setter;
57936
57937                         DUK_DD(DUK_DDPRINT("put to an own or inherited accessor, calling setter"));
57938
57939                         setter = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, curr, desc.e_idx);
57940                         if (!setter) {
57941                                 goto fail_no_setter;
57942                         }
57943                         duk_push_hobject(thr, setter);
57944                         duk_push_tval(thr, tv_obj);  /* note: original, uncoerced base */
57945                         duk_push_tval(thr, tv_val);  /* [key setter this val] */
57946 #if defined(DUK_USE_NONSTD_SETTER_KEY_ARGUMENT)
57947                         duk_dup_m4(thr);
57948                         duk_call_method(thr, 2);     /* [key setter this val key] -> [key retval] */
57949 #else
57950                         duk_call_method(thr, 1);     /* [key setter this val] -> [key retval] */
57951 #endif
57952                         duk_pop_unsafe(thr);         /* ignore retval -> [key] */
57953                         goto success_no_arguments_exotic;
57954                 }
57955
57956                 if (orig == NULL) {
57957                         /*
57958                          *  Found existing own or inherited plain property, but original
57959                          *  base is a primitive value.
57960                          */
57961                         DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
57962                         goto fail_base_primitive;
57963                 }
57964
57965                 if (curr != orig) {
57966                         /*
57967                          *  Found existing inherited plain property.
57968                          *  Do an access control check, and if OK, write
57969                          *  new property to 'orig'.
57970                          */
57971                         if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
57972                                 DUK_DD(DUK_DDPRINT("found existing inherited plain property, but original object is not extensible"));
57973                                 goto fail_not_extensible;
57974                         }
57975                         if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
57976                                 DUK_DD(DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable"));
57977                                 goto fail_not_writable;
57978                         }
57979                         DUK_DD(DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable"));
57980                         goto create_new;
57981                 } else {
57982                         /*
57983                          *  Found existing own (non-inherited) plain property.
57984                          *  Do an access control check and update in place.
57985                          */
57986
57987                         if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
57988                                 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable"));
57989                                 goto fail_not_writable;
57990                         }
57991                         if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
57992                                 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable"));
57993
57994                                 if (DUK_HOBJECT_IS_ARRAY(curr)) {
57995                                         /*
57996                                          *  Write to 'length' of an array is a very complex case
57997                                          *  handled in a helper which updates both the array elements
57998                                          *  and writes the new 'length'.  The write may result in an
57999                                          *  unconditional RangeError or a partial write (indicated
58000                                          *  by a return code).
58001                                          *
58002                                          *  Note: the helper has an unnecessary writability check
58003                                          *  for 'length', we already know it is writable.
58004                                          */
58005                                         DUK_ASSERT(key == DUK_HTHREAD_STRING_LENGTH(thr));  /* only virtual array property */
58006
58007                                         DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper"));
58008
58009                                         /* XXX: the helper currently assumes stack top contains new
58010                                          * 'length' value and the whole calling convention is not very
58011                                          * compatible with what we need.
58012                                          */
58013
58014                                         duk_push_tval(thr, tv_val);  /* [key val] */
58015                                         rc = duk__handle_put_array_length(thr, orig);
58016                                         duk_pop_unsafe(thr);  /* [key val] -> [key] */
58017                                         if (!rc) {
58018                                                 goto fail_array_length_partial;
58019                                         }
58020
58021                                         /* key is 'length', cannot match argument exotic behavior */
58022                                         goto success_no_arguments_exotic;
58023                                 }
58024 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
58025                                 else if (DUK_HOBJECT_IS_BUFOBJ(curr)) {
58026                                         duk_hbufobj *h_bufobj;
58027                                         duk_uint_t byte_off;
58028                                         duk_small_uint_t elem_size;
58029
58030                                         h_bufobj = (duk_hbufobj *) curr;
58031                                         DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
58032
58033                                         DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object"));
58034
58035                                         /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
58036                                          * length downshift won't.
58037                                          */
58038                                         if (arr_idx < (h_bufobj->length >> h_bufobj->shift) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
58039                                                 duk_uint8_t *data;
58040                                                 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
58041
58042                                                 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);  /* index/length check guarantees */
58043                                                 byte_off = arr_idx << h_bufobj->shift;       /* no wrap assuming h_bufobj->length is valid */
58044                                                 elem_size = (duk_small_uint_t) (1U << h_bufobj->shift);
58045
58046                                                 /* Coerce to number before validating pointers etc so that the
58047                                                  * number coercions in duk_hbufobj_validated_write() are
58048                                                  * guaranteed to be side effect free and not invalidate the
58049                                                  * pointer checks we do here.
58050                                                  */
58051                                                 duk_push_tval(thr, tv_val);
58052                                                 (void) duk_to_number_m1(thr);
58053
58054                                                 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
58055                                                         data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
58056                                                         duk_hbufobj_validated_write(thr, h_bufobj, data, elem_size);
58057                                                 } else {
58058                                                         DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
58059                                                 }
58060                                                 duk_pop_unsafe(thr);
58061                                                 goto success_no_arguments_exotic;
58062                                         }
58063                                 }
58064 #endif  /* DUK_USE_BUFFEROBJECT_SUPPORT */
58065
58066                                 DUK_D(DUK_DPRINT("should not happen, key %!O", key));
58067                                 goto fail_internal;  /* should not happen */
58068                         }
58069                         DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable"));
58070                         goto update_old;
58071                 }
58072                 DUK_UNREACHABLE();
58073
58074          next_in_chain:
58075                 /* XXX: option to pretend property doesn't exist if sanity limit is
58076                  * hit might be useful.
58077                  */
58078                 if (DUK_UNLIKELY(sanity-- == 0)) {
58079                         DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
58080                         DUK_WO_NORETURN(return 0;);
58081                 }
58082                 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
58083         } while (curr != NULL);
58084
58085         /*
58086          *  Property not found in prototype chain.
58087          */
58088
58089         DUK_DDD(DUK_DDDPRINT("property not found in prototype chain"));
58090
58091         if (orig == NULL) {
58092                 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
58093                 goto fail_base_primitive;
58094         }
58095
58096         if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
58097                 DUK_DD(DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible"));
58098                 goto fail_not_extensible;
58099         }
58100
58101         goto create_new;
58102
58103  update_old:
58104
58105         /*
58106          *  Update an existing property of the base object.
58107          */
58108
58109         /* [key] */
58110
58111         DUK_DDD(DUK_DDDPRINT("update an existing property of the original object"));
58112
58113         DUK_ASSERT(orig != NULL);
58114 #if defined(DUK_USE_ROM_OBJECTS)
58115         /* This should not happen because DUK_TAG_OBJECT case checks
58116          * for this already, but check just in case.
58117          */
58118         if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
58119                 goto fail_not_writable;
58120         }
58121 #endif
58122
58123         /* Although there are writable virtual properties (e.g. plain buffer
58124          * and buffer object number indices), they are handled before we come
58125          * here.
58126          */
58127         DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
58128         DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
58129
58130         /* Array own property .length is handled above. */
58131         DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr)));
58132
58133         if (desc.e_idx >= 0) {
58134                 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
58135                 DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv));
58136                 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val);  /* side effects; e_idx may be invalidated */
58137                 /* don't touch property attributes or hash part */
58138                 DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT",
58139                                    (long) desc.e_idx, (duk_tval *) tv));
58140         } else {
58141                 /* Note: array entries are always writable, so the writability check
58142                  * above is pointless for them.  The check could be avoided with some
58143                  * refactoring but is probably not worth it.
58144                  */
58145
58146                 DUK_ASSERT(desc.a_idx >= 0);
58147                 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx);
58148                 DUK_DDD(DUK_DDDPRINT("previous array value: %!iT", (duk_tval *) tv));
58149                 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val);  /* side effects; a_idx may be invalidated */
58150                 DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT",
58151                                    (long) desc.a_idx, (duk_tval *) tv));
58152         }
58153
58154         /* Regardless of whether property is found in entry or array part,
58155          * it may have arguments exotic behavior (array indices may reside
58156          * in entry part for abandoned / non-existent array parts).
58157          */
58158         goto success_with_arguments_exotic;
58159
58160  create_new:
58161
58162         /*
58163          *  Create a new property in the original object.
58164          *
58165          *  Exotic properties need to be reconsidered here from a write
58166          *  perspective (not just property attributes perspective).
58167          *  However, the property does not exist in the object already,
58168          *  so this limits the kind of exotic properties that apply.
58169          */
58170
58171         /* [key] */
58172
58173         DUK_DDD(DUK_DDDPRINT("create new property to original object"));
58174
58175         DUK_ASSERT(orig != NULL);
58176
58177         /* Array own property .length is handled above. */
58178         DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr)));
58179
58180 #if defined(DUK_USE_ROM_OBJECTS)
58181         /* This should not happen because DUK_TAG_OBJECT case checks
58182          * for this already, but check just in case.
58183          */
58184         if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
58185                 goto fail_not_writable;
58186         }
58187 #endif
58188
58189         /* Not possible because array object 'length' is present
58190          * from its creation and cannot be deleted, and is thus
58191          * caught as an existing property above.
58192          */
58193         DUK_ASSERT(!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
58194                      key == DUK_HTHREAD_STRING_LENGTH(thr)));
58195
58196         if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
58197             arr_idx != DUK__NO_ARRAY_INDEX) {
58198                 /* automatic length update */
58199                 duk_uint32_t old_len;
58200                 duk_harray *a;
58201
58202                 a = (duk_harray *) orig;
58203                 DUK_ASSERT_HARRAY_VALID(a);
58204
58205                 old_len = a->length;
58206
58207                 if (arr_idx >= old_len) {
58208                         DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
58209                                              "(arr_idx=%ld, old_len=%ld)",
58210                                              (long) arr_idx, (long) old_len));
58211
58212                         if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
58213                                 DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable"));
58214                                 goto fail_not_writable;
58215                         }
58216
58217                         /* Note: actual update happens once write has been completed
58218                          * without error below.  The write should always succeed
58219                          * from a specification viewpoint, but we may e.g. run out
58220                          * of memory.  It's safer in this order.
58221                          */
58222
58223                         DUK_ASSERT(arr_idx != 0xffffffffUL);
58224                         new_array_length = arr_idx + 1;  /* flag for later write */
58225                 } else {
58226                         DUK_DDD(DUK_DDDPRINT("write new array entry does not require length update "
58227                                              "(arr_idx=%ld, old_len=%ld)",
58228                                              (long) arr_idx, (long) old_len));
58229                 }
58230         }
58231
58232  /* write_to_array_part: */
58233
58234         /*
58235          *  Write to array part?
58236          *
58237          *  Note: array abandonding requires a property resize which uses
58238          *  'rechecks' valstack for temporaries and may cause any existing
58239          *  valstack pointers to be invalidated.  To protect against this,
58240          *  tv_obj, tv_key, and tv_val are copies of the original inputs.
58241          */
58242
58243         if (arr_idx != DUK__NO_ARRAY_INDEX &&
58244             DUK_HOBJECT_HAS_ARRAY_PART(orig)) {
58245                 if (arr_idx < DUK_HOBJECT_GET_ASIZE(orig)) {
58246                         goto no_array_growth;
58247                 }
58248
58249                 /*
58250                  *  Array needs to grow, but we don't want it becoming too sparse.
58251                  *  If it were to become sparse, abandon array part, moving all
58252                  *  array entries into the entries part (for good).
58253                  *
58254                  *  Since we don't keep track of actual density (used vs. size) of
58255                  *  the array part, we need to estimate somehow.  The check is made
58256                  *  in two parts:
58257                  *
58258                  *    - Check whether the resize need is small compared to the
58259                  *      current size (relatively); if so, resize without further
58260                  *      checking (essentially we assume that the original part is
58261                  *      "dense" so that the result would be dense enough).
58262                  *
58263                  *    - Otherwise, compute the resize using an actual density
58264                  *      measurement based on counting the used array entries.
58265                  */
58266
58267                 DUK_DDD(DUK_DDDPRINT("write to new array requires array resize, decide whether to do a "
58268                                      "fast resize without abandon check (arr_idx=%ld, old_size=%ld)",
58269                                      (long) arr_idx, (long) DUK_HOBJECT_GET_ASIZE(orig)));
58270
58271                 if (duk__abandon_array_slow_check_required(arr_idx, DUK_HOBJECT_GET_ASIZE(orig))) {
58272                         duk_uint32_t old_used;
58273                         duk_uint32_t old_size;
58274
58275                         DUK_DDD(DUK_DDDPRINT("=> fast check is NOT OK, do slow check for array abandon"));
58276
58277                         duk__compute_a_stats(thr, orig, &old_used, &old_size);
58278
58279                         DUK_DDD(DUK_DDDPRINT("abandon check, array stats: old_used=%ld, old_size=%ld, arr_idx=%ld",
58280                                              (long) old_used, (long) old_size, (long) arr_idx));
58281
58282                         /* Note: intentionally use approximations to shave a few instructions:
58283                          *   a_used = old_used  (accurate: old_used + 1)
58284                          *   a_size = arr_idx   (accurate: arr_idx + 1)
58285                          */
58286                         if (duk__abandon_array_density_check(old_used, arr_idx)) {
58287                                 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
58288                                                    "decided to abandon array part (would become too sparse)"));
58289
58290                                 /* abandoning requires a props allocation resize and
58291                                  * 'rechecks' the valstack, invalidating any existing
58292                                  * valstack value pointers!
58293                                  */
58294                                 duk__abandon_array_checked(thr, orig);
58295                                 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig));
58296
58297                                 goto write_to_entry_part;
58298                         }
58299
58300                         DUK_DDD(DUK_DDDPRINT("=> decided to keep array part"));
58301                 } else {
58302                         DUK_DDD(DUK_DDDPRINT("=> fast resize is OK"));
58303                 }
58304
58305                 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
58306                                    "decided to extend current allocation"));
58307
58308                 duk__grow_props_for_array_item(thr, orig, arr_idx);
58309
58310          no_array_growth:
58311
58312                 /* Note: assume array part is comprehensive, so that either
58313                  * the write goes to the array part, or we've abandoned the
58314                  * array above (and will not come here).
58315                  */
58316
58317                 DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(orig));
58318                 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(orig));
58319
58320                 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, arr_idx);
58321                 /* prev value must be unused, no decref */
58322                 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
58323                 DUK_TVAL_SET_TVAL(tv, tv_val);
58324                 DUK_TVAL_INCREF(thr, tv);
58325                 DUK_DD(DUK_DDPRINT("put to new array entry: %ld -> %!T",
58326                                    (long) arr_idx, (duk_tval *) tv));
58327
58328                 /* Note: array part values are [[Writable]], [[Enumerable]],
58329                  * and [[Configurable]] which matches the required attributes
58330                  * here.
58331                  */
58332                 goto entry_updated;
58333         }
58334
58335  write_to_entry_part:
58336
58337         /*
58338          *  Write to entry part
58339          */
58340
58341         /* entry allocation updates hash part and increases the key
58342          * refcount; may need a props allocation resize but doesn't
58343          * 'recheck' the valstack.
58344          */
58345         e_idx = duk__hobject_alloc_entry_checked(thr, orig, key);
58346         DUK_ASSERT(e_idx >= 0);
58347
58348         tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx);
58349         /* prev value can be garbage, no decref */
58350         DUK_TVAL_SET_TVAL(tv, tv_val);
58351         DUK_TVAL_INCREF(thr, tv);
58352         DUK_HOBJECT_E_SET_FLAGS(thr->heap, orig, e_idx, DUK_PROPDESC_FLAGS_WEC);
58353         goto entry_updated;
58354
58355  entry_updated:
58356
58357         /*
58358          *  Possible pending array length update, which must only be done
58359          *  if the actual entry write succeeded.
58360          */
58361
58362         if (new_array_length > 0) {
58363                 /* Note: zero works as a "no update" marker because the new length
58364                  * can never be zero after a new property is written.
58365                  */
58366
58367                 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig));
58368
58369                 DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld",
58370                                      (long) new_array_length));
58371
58372                 ((duk_harray *) orig)->length = new_array_length;
58373         }
58374
58375         /*
58376          *  Arguments exotic behavior not possible for new properties: all
58377          *  magically bound properties are initially present in the arguments
58378          *  object, and if they are deleted, the binding is also removed from
58379          *  parameter map.
58380          */
58381
58382         goto success_no_arguments_exotic;
58383
58384  success_with_arguments_exotic:
58385
58386         /*
58387          *  Arguments objects have exotic [[DefineOwnProperty]] which updates
58388          *  the internal 'map' of arguments for writes to currently mapped
58389          *  arguments.  More conretely, writes to mapped arguments generate
58390          *  a write to a bound variable.
58391          *
58392          *  The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing
58393          *  data properties and new properties, but not for existing accessors.
58394          *  Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we
58395          *  have a Desc with 'Value' (and possibly other properties too), and
58396          *  we end up in step 5.b.i.
58397          */
58398
58399         if (arr_idx != DUK__NO_ARRAY_INDEX &&
58400             DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
58401                 /* Note: only numbered indices are relevant, so arr_idx fast reject
58402                  * is good (this is valid unless there are more than 4**32-1 arguments).
58403                  */
58404
58405                 DUK_DDD(DUK_DDDPRINT("putprop successful, arguments exotic behavior needed"));
58406
58407                 /* Note: we can reuse 'desc' here */
58408
58409                 /* XXX: top of stack must contain value, which helper doesn't touch,
58410                  * rework to use tv_val directly?
58411                  */
58412
58413                 duk_push_tval(thr, tv_val);
58414                 (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
58415                 duk_pop_unsafe(thr);
58416         }
58417         /* fall thru */
58418
58419  success_no_arguments_exotic:
58420         /* shared exit path now */
58421         DUK_DDD(DUK_DDDPRINT("result: success"));
58422         duk_pop_unsafe(thr);  /* remove key */
58423         return 1;
58424
58425 #if defined(DUK_USE_ES6_PROXY)
58426  fail_proxy_rejected:
58427         DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects"));
58428         if (throw_flag) {
58429                 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
58430                 DUK_WO_NORETURN(return 0;);
58431         }
58432         /* Note: no key on stack */
58433         return 0;
58434 #endif
58435
58436  fail_base_primitive:
58437         DUK_DDD(DUK_DDDPRINT("result: error, base primitive"));
58438         if (throw_flag) {
58439 #if defined(DUK_USE_PARANOID_ERRORS)
58440                 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
58441 #else
58442                 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
58443                                duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
58444 #endif
58445                 DUK_WO_NORETURN(return 0;);
58446         }
58447         duk_pop_unsafe(thr);  /* remove key */
58448         return 0;
58449
58450  fail_not_extensible:
58451         DUK_DDD(DUK_DDDPRINT("result: error, not extensible"));
58452         if (throw_flag) {
58453                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
58454                 DUK_WO_NORETURN(return 0;);
58455         }
58456         duk_pop_unsafe(thr);  /* remove key */
58457         return 0;
58458
58459  fail_not_writable:
58460         DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
58461         if (throw_flag) {
58462                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
58463                 DUK_WO_NORETURN(return 0;);
58464         }
58465         duk_pop_unsafe(thr);  /* remove key */
58466         return 0;
58467
58468 #if defined(DUK_USE_ROM_OBJECTS)
58469  fail_not_writable_no_pop:
58470         DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
58471         if (throw_flag) {
58472                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
58473                 DUK_WO_NORETURN(return 0;);
58474         }
58475         return 0;
58476 #endif
58477
58478  fail_array_length_partial:
58479         DUK_DD(DUK_DDPRINT("result: error, array length write only partially successful"));
58480         if (throw_flag) {
58481                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
58482                 DUK_WO_NORETURN(return 0;);
58483         }
58484         duk_pop_unsafe(thr);  /* remove key */
58485         return 0;
58486
58487  fail_no_setter:
58488         DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter"));
58489         if (throw_flag) {
58490                 DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
58491                 DUK_WO_NORETURN(return 0;);
58492         }
58493         duk_pop_unsafe(thr);  /* remove key */
58494         return 0;
58495
58496  fail_internal:
58497         DUK_DDD(DUK_DDDPRINT("result: error, internal"));
58498         if (throw_flag) {
58499                 DUK_ERROR_INTERNAL(thr);
58500                 DUK_WO_NORETURN(return 0;);
58501         }
58502         duk_pop_unsafe(thr);  /* remove key */
58503         return 0;
58504 }
58505
58506 /*
58507  *  ECMAScript compliant [[Delete]](P, Throw).
58508  */
58509
58510 DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
58511         duk_propdesc desc;
58512         duk_tval *tv;
58513         duk_uint32_t arr_idx;
58514         duk_bool_t throw_flag;
58515         duk_bool_t force_flag;
58516
58517         throw_flag = (flags & DUK_DELPROP_FLAG_THROW);
58518         force_flag = (flags & DUK_DELPROP_FLAG_FORCE);
58519
58520         DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)",
58521                              (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag,
58522                              (duk_heaphdr *) obj, (duk_heaphdr *) key));
58523
58524         DUK_ASSERT(thr != NULL);
58525         DUK_ASSERT(thr->heap != NULL);
58526         DUK_ASSERT(obj != NULL);
58527         DUK_ASSERT(key != NULL);
58528
58529         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
58530
58531         arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
58532
58533         /* 0 = don't push current value */
58534         if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) {  /* don't push value */
58535                 DUK_DDD(DUK_DDDPRINT("property not found, succeed always"));
58536                 goto success;
58537         }
58538
58539 #if defined(DUK_USE_ROM_OBJECTS)
58540         if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
58541                 DUK_DD(DUK_DDPRINT("attempt to delprop on read-only target object"));
58542                 goto fail_not_configurable;
58543         }
58544 #endif
58545
58546         if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0 && !force_flag) {
58547                 goto fail_not_configurable;
58548         }
58549         if (desc.a_idx < 0 && desc.e_idx < 0) {
58550                 /* Currently there are no deletable virtual properties, but
58551                  * with force_flag we might attempt to delete one.
58552                  */
58553                 DUK_DD(DUK_DDPRINT("delete failed: property found, force flag, but virtual (and implicitly non-configurable)"));
58554                 goto fail_virtual;
58555         }
58556
58557         if (desc.a_idx >= 0) {
58558                 DUK_ASSERT(desc.e_idx < 0);
58559
58560                 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
58561                 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv);  /* side effects */
58562                 goto success;
58563         } else {
58564                 DUK_ASSERT(desc.a_idx < 0);
58565
58566                 /* remove hash entry (no decref) */
58567 #if defined(DUK_USE_HOBJECT_HASH_PART)
58568                 if (desc.h_idx >= 0) {
58569                         duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
58570
58571                         DUK_DDD(DUK_DDDPRINT("removing hash entry at h_idx %ld", (long) desc.h_idx));
58572                         DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) > 0);
58573                         DUK_ASSERT((duk_uint32_t) desc.h_idx < DUK_HOBJECT_GET_HSIZE(obj));
58574                         h_base[desc.h_idx] = DUK__HASH_DELETED;
58575                 } else {
58576                         DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
58577                 }
58578 #else
58579                 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
58580 #endif
58581
58582                 /* Remove value.  This requires multiple writes so avoid side
58583                  * effects via no-refzero macros so that e_idx is not
58584                  * invalidated.
58585                  */
58586                 DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p",
58587                                      (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
58588                 DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx));
58589                 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) {
58590                         duk_hobject *tmp;
58591
58592                         tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
58593                         DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
58594                         DUK_UNREF(tmp);
58595                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
58596
58597                         tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
58598                         DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
58599                         DUK_UNREF(tmp);
58600                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
58601                 } else {
58602                         tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
58603                         DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
58604                 }
58605 #if 0
58606                 /* Not strictly necessary because if key == NULL, flag MUST be ignored. */
58607                 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0);
58608 #endif
58609
58610                 /* Remove key. */
58611                 DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p",
58612                                      (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
58613                 DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx));
58614                 DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx));
58615                 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL);
58616                 DUK_HSTRING_DECREF_NORZ(thr, key);
58617
58618                 /* Trigger refzero side effects only when we're done as a
58619                  * finalizer might operate on the object and affect the
58620                  * e_idx we're supposed to use.
58621                  */
58622                 DUK_REFZERO_CHECK_SLOW(thr);
58623                 goto success;
58624         }
58625
58626         DUK_UNREACHABLE();
58627
58628  success:
58629         /*
58630          *  Argument exotic [[Delete]] behavior (E5 Section 10.6) is
58631          *  a post-check, keeping arguments internal 'map' in sync with
58632          *  any successful deletes (note that property does not need to
58633          *  exist for delete to 'succeed').
58634          *
58635          *  Delete key from 'map'.  Since 'map' only contains array index
58636          *  keys, we can use arr_idx for a fast skip.
58637          */
58638
58639         DUK_DDD(DUK_DDDPRINT("delete successful, check for arguments exotic behavior"));
58640
58641         if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
58642                 /* Note: only numbered indices are relevant, so arr_idx fast reject
58643                  * is good (this is valid unless there are more than 4**32-1 arguments).
58644                  */
58645
58646                 DUK_DDD(DUK_DDDPRINT("delete successful, arguments exotic behavior needed"));
58647
58648                 /* Note: we can reuse 'desc' here */
58649                 (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc);
58650         }
58651
58652         DUK_DDD(DUK_DDDPRINT("delete successful"));
58653         return 1;
58654
58655  fail_virtual:  /* just use the same "not configurable" error message */
58656  fail_not_configurable:
58657         DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable"));
58658
58659         if (throw_flag) {
58660                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
58661                 DUK_WO_NORETURN(return 0;);
58662         }
58663         return 0;
58664 }
58665
58666 /*
58667  *  DELPROP: ECMAScript property deletion.
58668  */
58669
58670 DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
58671         duk_hstring *key = NULL;
58672 #if defined(DUK_USE_ES6_PROXY)
58673         duk_propdesc desc;
58674 #endif
58675         duk_int_t entry_top;
58676         duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
58677         duk_bool_t rc;
58678
58679         DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
58680                              (void *) thr, (void *) tv_obj, (void *) tv_key,
58681                              (duk_tval *) tv_obj, (duk_tval *) tv_key));
58682
58683         DUK_ASSERT(thr != NULL);
58684         DUK_ASSERT(thr->heap != NULL);
58685         DUK_ASSERT(tv_obj != NULL);
58686         DUK_ASSERT(tv_key != NULL);
58687
58688         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
58689
58690         /* Storing the entry top is cheaper here to ensure stack is correct at exit,
58691          * as there are several paths out.
58692          */
58693         entry_top = duk_get_top(thr);
58694
58695         if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
58696             DUK_TVAL_IS_NULL(tv_obj)) {
58697                 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
58698                 goto fail_invalid_base_uncond;
58699         }
58700
58701         duk_push_tval(thr, tv_obj);
58702         duk_push_tval(thr, tv_key);
58703
58704         tv_obj = DUK_GET_TVAL_NEGIDX(thr, -2);
58705         if (DUK_TVAL_IS_OBJECT(tv_obj)) {
58706                 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
58707                 DUK_ASSERT(obj != NULL);
58708
58709 #if defined(DUK_USE_ES6_PROXY)
58710                 if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(obj))) {
58711                         duk_hobject *h_target;
58712                         duk_bool_t tmp_bool;
58713
58714                         /* Note: proxy handling must happen before key is string coerced. */
58715
58716                         if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) {
58717                                 /* -> [ ... obj key trap handler ] */
58718                                 DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key));
58719                                 duk_push_hobject(thr, h_target);  /* target */
58720                                 duk_dup_m4(thr);  /* P */
58721                                 duk_call_method(thr, 2 /*nargs*/);
58722                                 tmp_bool = duk_to_boolean_top_pop(thr);
58723                                 if (!tmp_bool) {
58724                                         goto fail_proxy_rejected;  /* retval indicates delete failed */
58725                                 }
58726
58727                                 /* Target object must be checked for a conflicting
58728                                  * non-configurable property.
58729                                  */
58730                                 tv_key = DUK_GET_TVAL_NEGIDX(thr, -1);
58731                                 arr_idx = duk__push_tval_to_property_key(thr, tv_key, &key);
58732                                 DUK_ASSERT(key != NULL);
58733
58734                                 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) {  /* don't push value */
58735                                         duk_small_int_t desc_reject;
58736
58737                                         DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for "
58738                                                              "conflicting property; desc.flags=0x%08lx, "
58739                                                              "desc.get=%p, desc.set=%p",
58740                                                              (duk_heaphdr *) key, (unsigned long) desc.flags,
58741                                                              (void *) desc.get, (void *) desc.set));
58742
58743                                         desc_reject = !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE);
58744                                         if (desc_reject) {
58745                                                 /* unconditional */
58746                                                 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
58747                                                 DUK_WO_NORETURN(return 0;);
58748                                         }
58749                                 }
58750                                 rc = 1;  /* success */
58751                                 goto done_rc;
58752                         }
58753
58754                         obj = h_target;  /* resume delete to target */
58755                 }
58756 #endif  /* DUK_USE_ES6_PROXY */
58757
58758                 arr_idx = duk__to_property_key(thr, -1, &key);
58759                 DUK_ASSERT(key != NULL);
58760
58761                 rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0);
58762                 goto done_rc;
58763         } else if (DUK_TVAL_IS_STRING(tv_obj)) {
58764                 /* String has .length and array index virtual properties
58765                  * which can't be deleted.  No need for a symbol check;
58766                  * no offending virtual symbols exist.
58767                  */
58768                 /* XXX: unnecessary string coercion for array indices,
58769                  * intentional to keep small.
58770                  */
58771                 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
58772                 DUK_ASSERT(h != NULL);
58773
58774                 arr_idx = duk__to_property_key(thr, -1, &key);
58775                 DUK_ASSERT(key != NULL);
58776
58777                 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
58778                         goto fail_not_configurable;
58779                 }
58780
58781                 if (arr_idx != DUK__NO_ARRAY_INDEX &&
58782                     arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
58783                         goto fail_not_configurable;
58784                 }
58785         } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
58786                 /* XXX: unnecessary string coercion for array indices,
58787                  * intentional to keep small; some overlap with string
58788                  * handling.
58789                  */
58790                 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
58791                 DUK_ASSERT(h != NULL);
58792
58793                 arr_idx = duk__to_property_key(thr, -1, &key);
58794                 DUK_ASSERT(key != NULL);
58795
58796                 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
58797                         goto fail_not_configurable;
58798                 }
58799
58800                 if (arr_idx != DUK__NO_ARRAY_INDEX &&
58801                     arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
58802                         goto fail_not_configurable;
58803                 }
58804         } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
58805                 /* Lightfunc has no virtual properties since Duktape 2.2
58806                  * so success.  Still must coerce key for side effects.
58807                  */
58808
58809                 arr_idx = duk__to_property_key(thr, -1, &key);
58810                 DUK_ASSERT(key != NULL);
58811                 DUK_UNREF(key);
58812         }
58813
58814         /* non-object base, no offending virtual property */
58815         rc = 1;
58816         goto done_rc;
58817
58818  done_rc:
58819         duk_set_top_unsafe(thr, entry_top);
58820         return rc;
58821
58822  fail_invalid_base_uncond:
58823         /* Note: unconditional throw */
58824         DUK_ASSERT(duk_get_top(thr) == entry_top);
58825 #if defined(DUK_USE_PARANOID_ERRORS)
58826         DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
58827 #else
58828         DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
58829                        duk_push_string_tval_readable(thr, tv_key), duk_push_string_tval_readable(thr, tv_obj));
58830 #endif
58831         DUK_WO_NORETURN(return 0;);
58832
58833 #if defined(DUK_USE_ES6_PROXY)
58834  fail_proxy_rejected:
58835         if (throw_flag) {
58836                 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
58837                 DUK_WO_NORETURN(return 0;);
58838         }
58839         duk_set_top_unsafe(thr, entry_top);
58840         return 0;
58841 #endif
58842
58843  fail_not_configurable:
58844         if (throw_flag) {
58845                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
58846                 DUK_WO_NORETURN(return 0;);
58847         }
58848         duk_set_top_unsafe(thr, entry_top);
58849         return 0;
58850 }
58851
58852 /*
58853  *  Internal helper to define a property with specific flags, ignoring
58854  *  normal semantics such as extensibility, write protection etc.
58855  *  Overwrites any existing value and attributes unless caller requests
58856  *  that value only be updated if it doesn't already exists.
58857  *
58858  *  Does not support:
58859  *    - virtual properties (error if write attempted)
58860  *    - getter/setter properties (error if write attempted)
58861  *    - non-default (!= WEC) attributes for array entries (error if attempted)
58862  *    - array abandoning: if array part exists, it is always extended
58863  *    - array 'length' updating
58864  *
58865  *  Stack: [... in_val] -> []
58866  *
58867  *  Used for e.g. built-in initialization and environment record
58868  *  operations.
58869  */
58870
58871 DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
58872         duk_propdesc desc;
58873         duk_uint32_t arr_idx;
58874         duk_int_t e_idx;
58875         duk_tval *tv1 = NULL;
58876         duk_tval *tv2 = NULL;
58877         duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK;  /* mask out flags not actually stored */
58878
58879         DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
58880                              (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
58881                              (unsigned long) flags, (duk_tval *) duk_get_tval(thr, -1)));
58882
58883         DUK_ASSERT(thr != NULL);
58884         DUK_ASSERT(thr->heap != NULL);
58885         DUK_ASSERT(obj != NULL);
58886         DUK_ASSERT(key != NULL);
58887         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
58888         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
58889         DUK_ASSERT(duk_is_valid_index(thr, -1));  /* contains value */
58890
58891         arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
58892
58893         if (duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) {  /* don't push value */
58894                 if (desc.e_idx >= 0) {
58895                         if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
58896                                 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> skip as requested"));
58897                                 goto pop_exit;
58898                         }
58899                         DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> update value and attributes"));
58900                         if (DUK_UNLIKELY(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx))) {
58901                                 DUK_D(DUK_DPRINT("existing property is an accessor, not supported"));
58902                                 goto error_internal;
58903                         }
58904
58905                         DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, propflags);
58906                         tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
58907                 } else if (desc.a_idx >= 0) {
58908                         if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
58909                                 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> skip as requested"));
58910                                 goto pop_exit;
58911                         }
58912                         DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)"));
58913                         if (propflags != DUK_PROPDESC_FLAGS_WEC) {
58914                                 DUK_D(DUK_DPRINT("existing property in array part, but propflags not WEC (0x%02lx)",
58915                                                  (unsigned long) propflags));
58916                                 goto error_internal;
58917                         }
58918
58919                         tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
58920                 } else {
58921                         if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
58922                                 DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested"));
58923                                 goto pop_exit;
58924                         }
58925                         if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
58926                                 duk_uint32_t new_len;
58927 #if defined(DUK_USE_DEBUG)
58928                                 duk_uint32_t prev_len;
58929                                 prev_len = ((duk_harray *) obj)->length;
58930 #endif
58931                                 new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(thr, -1));
58932                                 ((duk_harray *) obj)->length = new_len;
58933                                 DUK_D(DUK_DPRINT("internal define property for array .length: %ld -> %ld",
58934                                                  (long) prev_len, (long) ((duk_harray *) obj)->length));
58935                                 goto pop_exit;
58936                         }
58937                         DUK_DD(DUK_DDPRINT("property already exists but is virtual -> failure"));
58938                         goto error_virtual;
58939                 }
58940
58941                 goto write_value;
58942         }
58943
58944         if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
58945                 if (arr_idx != DUK__NO_ARRAY_INDEX) {
58946                         DUK_DDD(DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)"));
58947                         DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC);
58948
58949                         /* always grow the array, no sparse / abandon support here */
58950                         if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
58951                                 duk__grow_props_for_array_item(thr, obj, arr_idx);
58952                         }
58953
58954                         DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
58955                         tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
58956                         goto write_value;
58957                 }
58958         }
58959
58960         DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes"));
58961         e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);  /* increases key refcount */
58962         DUK_ASSERT(e_idx >= 0);
58963         DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags);
58964         tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
58965         /* new entry: previous value is garbage; set to undefined to share write_value */
58966         DUK_TVAL_SET_UNDEFINED(tv1);
58967         goto write_value;
58968
58969  write_value:
58970         /* tv1 points to value storage */
58971
58972         tv2 = duk_require_tval(thr, -1);  /* late lookup, avoid side effects */
58973         DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T",
58974                              (duk_tval *) tv1, (duk_tval *) tv2));
58975
58976         DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2);  /* side effects */
58977         goto pop_exit;
58978
58979  pop_exit:
58980         duk_pop_unsafe(thr);  /* remove in_val */
58981         return;
58982
58983  error_virtual:  /* share error message */
58984  error_internal:
58985         DUK_ERROR_INTERNAL(thr);
58986         DUK_WO_NORETURN(return;);
58987 }
58988
58989 /*
58990  *  Fast path for defining array indexed values without interning the key.
58991  *  This is used by e.g. code for Array prototype and traceback creation so
58992  *  must avoid interning.
58993  */
58994
58995 DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) {
58996         duk_hstring *key;
58997         duk_tval *tv1, *tv2;
58998
58999         DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
59000                              "arr_idx=%ld, flags=0x%02lx, val=%!T",
59001                              (void *) thr, obj, (long) arr_idx, (unsigned long) flags,
59002                              (duk_tval *) duk_get_tval(thr, -1)));
59003
59004         DUK_ASSERT(thr != NULL);
59005         DUK_ASSERT(thr->heap != NULL);
59006         DUK_ASSERT(obj != NULL);
59007         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
59008
59009         if (DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
59010             arr_idx != DUK__NO_ARRAY_INDEX &&
59011             flags == DUK_PROPDESC_FLAGS_WEC) {
59012                 DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0);  /* covered by comparison */
59013
59014                 DUK_DDD(DUK_DDDPRINT("define property to array part (property may or may not exist yet)"));
59015
59016                 /* always grow the array, no sparse / abandon support here */
59017                 if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
59018                         duk__grow_props_for_array_item(thr, obj, arr_idx);
59019                 }
59020
59021                 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
59022                 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
59023                 tv2 = duk_require_tval(thr, -1);
59024
59025                 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2);  /* side effects */
59026
59027                 duk_pop_unsafe(thr);  /* [ ...val ] -> [ ... ] */
59028                 return;
59029         }
59030
59031         DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path"));
59032
59033         key = duk_push_uint_to_hstring(thr, (duk_uint_t) arr_idx);
59034         DUK_ASSERT(key != NULL);
59035         duk_insert(thr, -2);  /* [ ... val key ] -> [ ... key val ] */
59036
59037         duk_hobject_define_property_internal(thr, obj, key, flags);
59038
59039         duk_pop_unsafe(thr);  /* [ ... key ] -> [ ... ] */
59040 }
59041
59042 /*
59043  *  Internal helpers for managing object 'length'
59044  */
59045
59046 DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
59047         duk_double_t val;
59048
59049         DUK_ASSERT_CTX_VALID(thr);
59050         DUK_ASSERT(obj != NULL);
59051
59052         /* Fast path for Arrays. */
59053         if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
59054                 return ((duk_harray *) obj)->length;
59055         }
59056
59057         /* Slow path, .length can be e.g. accessor, obj can be a Proxy, etc. */
59058         duk_push_hobject(thr, obj);
59059         duk_push_hstring_stridx(thr, DUK_STRIDX_LENGTH);
59060         (void) duk_hobject_getprop(thr,
59061                                    DUK_GET_TVAL_NEGIDX(thr, -2),
59062                                    DUK_GET_TVAL_NEGIDX(thr, -1));
59063         val = duk_to_number_m1(thr);
59064         duk_pop_3_unsafe(thr);
59065
59066         /* This isn't part of ECMAScript semantics; return a value within
59067          * duk_size_t range, or 0 otherwise.
59068          */
59069         if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) {
59070                 return (duk_size_t) val;
59071         }
59072         return 0;
59073 }
59074
59075 /*
59076  *  Fast finalizer check for an object.  Walks the prototype chain, checking
59077  *  for finalizer presence using DUK_HOBJECT_FLAG_HAVE_FINALIZER which is kept
59078  *  in sync with the actual property when setting/removing the finalizer.
59079  */
59080
59081 #if defined(DUK_USE_HEAPPTR16)
59082 DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_heap *heap, duk_hobject *obj) {
59083 #else
59084 DUK_INTERNAL duk_bool_t duk_hobject_has_finalizer_fast_raw(duk_hobject *obj) {
59085 #endif
59086         duk_uint_t sanity;
59087
59088         DUK_ASSERT(obj != NULL);
59089
59090         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
59091         do {
59092                 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_HAVE_FINALIZER(obj))) {
59093                         return 1;
59094                 }
59095                 if (DUK_UNLIKELY(sanity-- == 0)) {
59096                         DUK_D(DUK_DPRINT("prototype loop when checking for finalizer existence; returning false"));
59097                         return 0;
59098                 }
59099 #if defined(DUK_USE_HEAPPTR16)
59100                 DUK_ASSERT(heap != NULL);
59101                 obj = DUK_HOBJECT_GET_PROTOTYPE(heap, obj);
59102 #else
59103                 obj = DUK_HOBJECT_GET_PROTOTYPE(NULL, obj);  /* 'heap' arg ignored */
59104 #endif
59105         } while (obj != NULL);
59106
59107         return 0;
59108 }
59109
59110 /*
59111  *  Object.getOwnPropertyDescriptor()  (E5 Sections 15.2.3.3, 8.10.4)
59112  *
59113  *  [ ... key ] -> [ ... desc/undefined ]
59114  */
59115
59116 DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_hthread *thr, duk_idx_t obj_idx) {
59117         duk_hobject *obj;
59118         duk_hstring *key;
59119         duk_propdesc pd;
59120
59121         DUK_ASSERT(thr != NULL);
59122         DUK_ASSERT(thr->heap != NULL);
59123
59124         obj = duk_require_hobject_promote_mask(thr, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
59125         key = duk_to_property_key_hstring(thr, -1);
59126         DUK_ASSERT(key != NULL);
59127
59128         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
59129
59130         if (!duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE)) {
59131                 duk_push_undefined(thr);
59132                 duk_remove_m2(thr);
59133                 return;
59134         }
59135
59136         duk_push_object(thr);
59137
59138         /* [ ... key value desc ] */
59139
59140         if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
59141                 /* If a setter/getter is missing (undefined), the descriptor must
59142                  * still have the property present with the value 'undefined'.
59143                  */
59144                 if (pd.get) {
59145                         duk_push_hobject(thr, pd.get);
59146                 } else {
59147                         duk_push_undefined(thr);
59148                 }
59149                 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_GET);
59150                 if (pd.set) {
59151                         duk_push_hobject(thr, pd.set);
59152                 } else {
59153                         duk_push_undefined(thr);
59154                 }
59155                 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_SET);
59156         } else {
59157                 duk_dup_m2(thr);
59158                 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_VALUE);
59159                 duk_push_boolean(thr, DUK_PROPDESC_IS_WRITABLE(&pd));
59160                 duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_WRITABLE);
59161         }
59162         duk_push_boolean(thr, DUK_PROPDESC_IS_ENUMERABLE(&pd));
59163         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_ENUMERABLE);
59164         duk_push_boolean(thr, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
59165         duk_put_prop_stridx_short(thr, -2, DUK_STRIDX_CONFIGURABLE);
59166
59167         /* [ ... key value desc ] */
59168
59169         duk_replace(thr, -3);
59170         duk_pop_unsafe(thr);  /* -> [ ... desc ] */
59171 }
59172
59173 /*
59174  *  NormalizePropertyDescriptor() related helper.
59175  *
59176  *  Internal helper which validates and normalizes a property descriptor
59177  *  represented as an ECMAScript object (e.g. argument to defineProperty()).
59178  *  The output of this conversion is a set of defprop_flags and possibly
59179  *  some values pushed on the value stack to (1) ensure borrowed pointers
59180  *  remain valid, and (2) avoid unnecessary pops for footprint reasons.
59181  *  Caller must manage stack top carefully because the number of values
59182  *  pushed depends on the input property descriptor.
59183  *
59184  *  The original descriptor object must not be altered in the process.
59185  */
59186
59187 /* XXX: very basic optimization -> duk_get_prop_stridx_top */
59188
59189 DUK_INTERNAL
59190 void duk_hobject_prepare_property_descriptor(duk_hthread *thr,
59191                                              duk_idx_t idx_in,
59192                                              duk_uint_t *out_defprop_flags,
59193                                              duk_idx_t *out_idx_value,
59194                                              duk_hobject **out_getter,
59195                                              duk_hobject **out_setter) {
59196         duk_idx_t idx_value = -1;
59197         duk_hobject *getter = NULL;
59198         duk_hobject *setter = NULL;
59199         duk_bool_t is_data_desc = 0;
59200         duk_bool_t is_acc_desc = 0;
59201         duk_uint_t defprop_flags = 0;
59202
59203         DUK_ASSERT(out_defprop_flags != NULL);
59204         DUK_ASSERT(out_idx_value != NULL);
59205         DUK_ASSERT(out_getter != NULL);
59206         DUK_ASSERT(out_setter != NULL);
59207         DUK_ASSERT(idx_in <= 0x7fffL);  /* short variants would be OK, but not used to avoid shifts */
59208
59209         /* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */
59210         idx_in = duk_require_normalize_index(thr, idx_in);
59211         (void) duk_require_hobject(thr, idx_in);
59212
59213         /* The coercion order must match the ToPropertyDescriptor() algorithm
59214          * so that side effects in coercion happen in the correct order.
59215          * (This order also happens to be compatible with duk_def_prop(),
59216          * although it doesn't matter in practice.)
59217          */
59218
59219         if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_VALUE)) {
59220                 is_data_desc = 1;
59221                 defprop_flags |= DUK_DEFPROP_HAVE_VALUE;
59222                 idx_value = duk_get_top_index(thr);
59223         }
59224
59225         if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_WRITABLE)) {
59226                 is_data_desc = 1;
59227                 if (duk_to_boolean_top_pop(thr)) {
59228                         defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
59229                 } else {
59230                         defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
59231                 }
59232         }
59233
59234         if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_GET)) {
59235                 duk_tval *tv = duk_require_tval(thr, -1);
59236                 duk_hobject *h_get;
59237
59238                 if (DUK_TVAL_IS_UNDEFINED(tv)) {
59239                         /* undefined is accepted */
59240                         DUK_ASSERT(getter == NULL);
59241                 } else {
59242                         /* NOTE: lightfuncs are coerced to full functions because
59243                          * lightfuncs don't fit into a property value slot.  This
59244                          * has some side effects, see test-dev-lightfunc-accessor.js.
59245                          */
59246                         h_get = duk_get_hobject_promote_lfunc(thr, -1);
59247                         if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) {
59248                                 goto type_error;
59249                         }
59250                         getter = h_get;
59251                 }
59252                 is_acc_desc = 1;
59253                 defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
59254         }
59255
59256         if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_SET)) {
59257                 duk_tval *tv = duk_require_tval(thr, -1);
59258                 duk_hobject *h_set;
59259
59260                 if (DUK_TVAL_IS_UNDEFINED(tv)) {
59261                         /* undefined is accepted */
59262                         DUK_ASSERT(setter == NULL);
59263                 }  else {
59264                         /* NOTE: lightfuncs are coerced to full functions because
59265                          * lightfuncs don't fit into a property value slot.  This
59266                          * has some side effects, see test-dev-lightfunc-accessor.js.
59267                          */
59268                         h_set = duk_get_hobject_promote_lfunc(thr, -1);
59269                         if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) {
59270                                 goto type_error;
59271                         }
59272                         setter = h_set;
59273                 }
59274                 is_acc_desc = 1;
59275                 defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
59276         }
59277
59278         if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_ENUMERABLE)) {
59279                 if (duk_to_boolean_top_pop(thr)) {
59280                         defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
59281                 } else {
59282                         defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
59283                 }
59284         }
59285
59286         if (duk_get_prop_stridx(thr, idx_in, DUK_STRIDX_CONFIGURABLE)) {
59287                 if (duk_to_boolean_top_pop(thr)) {
59288                         defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
59289                 } else {
59290                         defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
59291                 }
59292         }
59293
59294         if (is_data_desc && is_acc_desc) {
59295                 goto type_error;
59296         }
59297
59298         *out_defprop_flags = defprop_flags;
59299         *out_idx_value = idx_value;
59300         *out_getter = getter;
59301         *out_setter = setter;
59302
59303         /* [ ... [multiple values] ] */
59304         return;
59305
59306  type_error:
59307         DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
59308         DUK_WO_NORETURN(return;);
59309 }
59310
59311 /*
59312  *  Object.defineProperty() related helper (E5 Section 15.2.3.6).
59313  *  Also handles ES2015 Reflect.defineProperty().
59314  *
59315  *  Inlines all [[DefineOwnProperty]] exotic behaviors.
59316  *
59317  *  Note: ECMAScript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
59318  *  implemented directly, but Object.defineProperty() serves its purpose.
59319  *  We don't need the [[DefineOwnProperty]] internally and we don't have a
59320  *  property descriptor with 'missing values' so it's easier to avoid it
59321  *  entirely.
59322  *
59323  *  Note: this is only called for actual objects, not primitive values.
59324  *  This must support virtual properties for full objects (e.g. Strings)
59325  *  but not for plain values (e.g. strings).  Lightfuncs, even though
59326  *  primitive in a sense, are treated like objects and accepted as target
59327  *  values.
59328  */
59329
59330 /* XXX: this is a major target for size optimization */
59331 DUK_INTERNAL
59332 duk_bool_t duk_hobject_define_property_helper(duk_hthread *thr,
59333                                               duk_uint_t defprop_flags,
59334                                               duk_hobject *obj,
59335                                               duk_hstring *key,
59336                                               duk_idx_t idx_value,
59337                                               duk_hobject *get,
59338                                               duk_hobject *set,
59339                                               duk_bool_t throw_flag) {
59340         duk_uint32_t arr_idx;
59341         duk_tval tv;
59342         duk_bool_t has_enumerable;
59343         duk_bool_t has_configurable;
59344         duk_bool_t has_writable;
59345         duk_bool_t has_value;
59346         duk_bool_t has_get;
59347         duk_bool_t has_set;
59348         duk_bool_t is_enumerable;
59349         duk_bool_t is_configurable;
59350         duk_bool_t is_writable;
59351         duk_bool_t force_flag;
59352         duk_small_uint_t new_flags;
59353         duk_propdesc curr;
59354         duk_uint32_t arridx_new_array_length;  /* != 0 => post-update for array 'length' (used when key is an array index) */
59355         duk_uint32_t arrlen_old_len;
59356         duk_uint32_t arrlen_new_len;
59357         duk_bool_t pending_write_protect;
59358
59359         DUK_ASSERT(thr != NULL);
59360         DUK_ASSERT(thr->heap != NULL);
59361         DUK_ASSERT(obj != NULL);
59362         DUK_ASSERT(key != NULL);
59363         /* idx_value may be < 0 (no value), set and get may be NULL */
59364
59365         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
59366
59367         /* All the flags fit in 16 bits, so will fit into duk_bool_t. */
59368
59369         has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE);
59370         has_enumerable = (defprop_flags & DUK_DEFPROP_HAVE_ENUMERABLE);
59371         has_configurable = (defprop_flags & DUK_DEFPROP_HAVE_CONFIGURABLE);
59372         has_value = (defprop_flags & DUK_DEFPROP_HAVE_VALUE);
59373         has_get = (defprop_flags & DUK_DEFPROP_HAVE_GETTER);
59374         has_set = (defprop_flags & DUK_DEFPROP_HAVE_SETTER);
59375         is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE);
59376         is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE);
59377         is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE);
59378         force_flag = (defprop_flags & DUK_DEFPROP_FORCE);
59379
59380         arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
59381
59382         arridx_new_array_length = 0;
59383         pending_write_protect = 0;
59384         arrlen_old_len = 0;
59385         arrlen_new_len = 0;
59386
59387         DUK_DDD(DUK_DDDPRINT("has_enumerable=%ld is_enumerable=%ld "
59388                              "has_configurable=%ld is_configurable=%ld "
59389                              "has_writable=%ld is_writable=%ld "
59390                              "has_value=%ld value=%!T "
59391                              "has_get=%ld get=%p=%!O "
59392                              "has_set=%ld set=%p=%!O "
59393                              "arr_idx=%ld throw_flag=!%ld",
59394                              (long) has_enumerable, (long) is_enumerable,
59395                              (long) has_configurable, (long) is_configurable,
59396                              (long) has_writable, (long) is_writable,
59397                              (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(thr, idx_value) : NULL),
59398                              (long) has_get, (void *) get, (duk_heaphdr *) get,
59399                              (long) has_set, (void *) set, (duk_heaphdr *) set,
59400                              (long) arr_idx, (long) throw_flag));
59401
59402         /*
59403          *  Array exotic behaviors can be implemented at this point.  The local variables
59404          *  are essentially a 'value copy' of the input descriptor (Desc), which is modified
59405          *  by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1).
59406          */
59407
59408         if (!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
59409                 goto skip_array_exotic;
59410         }
59411
59412         if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
59413                 duk_harray *a;
59414
59415                 /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */
59416                 if (!has_value) {
59417                         DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior"));
59418                         goto skip_array_exotic;
59419                 }
59420
59421                 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', value present in descriptor -> exotic behavior"));
59422
59423                 /*
59424                  *  Get old and new length
59425                  */
59426
59427                 a = (duk_harray *) obj;
59428                 DUK_ASSERT_HARRAY_VALID(a);
59429                 arrlen_old_len = a->length;
59430
59431                 DUK_ASSERT(idx_value >= 0);
59432                 arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(thr, idx_value));
59433                 duk_push_u32(thr, arrlen_new_len);
59434                 duk_replace(thr, idx_value);  /* step 3.e: replace 'Desc.[[Value]]' */
59435
59436                 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len));
59437
59438                 if (arrlen_new_len >= arrlen_old_len) {
59439                         /* standard behavior, step 3.f.i */
59440                         DUK_DDD(DUK_DDDPRINT("new length is same or higher as previous => standard behavior"));
59441                         goto skip_array_exotic;
59442                 }
59443                 DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior"));
59444
59445                 /* XXX: consolidated algorithm step 15.f -> redundant? */
59446                 if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) {
59447                         /* Array .length is always non-configurable; if it's also
59448                          * non-writable, don't allow it to be written.
59449                          */
59450                         goto fail_not_configurable;
59451                 }
59452
59453                 /* steps 3.h and 3.i */
59454                 if (has_writable && !is_writable) {
59455                         DUK_DDD(DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect"));
59456                         is_writable = 1;
59457                         pending_write_protect = 1;
59458                 }
59459
59460                 /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */
59461         } else if (arr_idx != DUK__NO_ARRAY_INDEX) {
59462                 /* XXX: any chance of unifying this with the 'length' key handling? */
59463
59464                 /* E5 Section 15.4.5.1, step 4 */
59465                 duk_uint32_t old_len;
59466                 duk_harray *a;
59467
59468                 a = (duk_harray *) obj;
59469                 DUK_ASSERT_HARRAY_VALID(a);
59470
59471                 old_len = a->length;
59472
59473                 if (arr_idx >= old_len) {
59474                         DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update "
59475                                              "(arr_idx=%ld, old_len=%ld)",
59476                                              (long) arr_idx, (long) old_len));
59477
59478                         if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) {
59479                                 /* Array .length is always non-configurable, so
59480                                  * if it's also non-writable, don't allow a value
59481                                  * write.  With force flag allow writing.
59482                                  */
59483                                 goto fail_not_configurable;
59484                         }
59485
59486                         /* actual update happens once write has been completed without
59487                          * error below.
59488                          */
59489                         DUK_ASSERT(arr_idx != 0xffffffffUL);
59490                         arridx_new_array_length = arr_idx + 1;
59491                 } else {
59492                         DUK_DDD(DUK_DDDPRINT("defineProperty does not require length update "
59493                                              "(arr_idx=%ld, old_len=%ld) -> standard behavior",
59494                                              (long) arr_idx, (long) old_len));
59495                 }
59496         }
59497  skip_array_exotic:
59498
59499         /* XXX: There is currently no support for writing buffer object
59500          * indexed elements here.  Attempt to do so will succeed and
59501          * write a concrete property into the buffer object.  This should
59502          * be fixed at some point but because buffers are a custom feature
59503          * anyway, this is relatively unimportant.
59504          */
59505
59506         /*
59507          *  Actual Object.defineProperty() default algorithm.
59508          */
59509
59510         /*
59511          *  First check whether property exists; if not, simple case.  This covers
59512          *  steps 1-4.
59513          */
59514
59515         if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE)) {
59516                 DUK_DDD(DUK_DDDPRINT("property does not exist"));
59517
59518                 if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj) && !force_flag) {
59519                         goto fail_not_extensible;
59520                 }
59521
59522 #if defined(DUK_USE_ROM_OBJECTS)
59523                 /* ROM objects are never extensible but force flag may
59524                  * allow us to come here anyway.
59525                  */
59526                 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj) || !DUK_HOBJECT_HAS_EXTENSIBLE(obj));
59527                 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
59528                         DUK_D(DUK_DPRINT("attempt to define property on a read-only target object"));
59529                         goto fail_not_configurable;
59530                 }
59531 #endif
59532
59533                 /* XXX: share final setting code for value and flags?  difficult because
59534                  * refcount code is different.  Share entry allocation?  But can't allocate
59535                  * until array index checked.
59536                  */
59537
59538                 /* steps 4.a and 4.b are tricky */
59539                 if (has_set || has_get) {
59540                         duk_int_t e_idx;
59541
59542                         DUK_DDD(DUK_DDDPRINT("create new accessor property"));
59543
59544                         DUK_ASSERT(has_set || set == NULL);
59545                         DUK_ASSERT(has_get || get == NULL);
59546                         DUK_ASSERT(!has_value);
59547                         DUK_ASSERT(!has_writable);
59548
59549                         new_flags = DUK_PROPDESC_FLAG_ACCESSOR;  /* defaults, E5 Section 8.6.1, Table 7 */
59550                         if (has_enumerable && is_enumerable) {
59551                                 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
59552                         }
59553                         if (has_configurable && is_configurable) {
59554                                 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
59555                         }
59556
59557                         if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
59558                                 DUK_DDD(DUK_DDDPRINT("accessor cannot go to array part, abandon array"));
59559                                 duk__abandon_array_checked(thr, obj);
59560                         }
59561
59562                         /* write to entry part */
59563                         e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);
59564                         DUK_ASSERT(e_idx >= 0);
59565
59566                         DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
59567                         DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set);
59568                         DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
59569                         DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
59570
59571                         DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
59572                         goto success_exotics;
59573                 } else {
59574                         duk_int_t e_idx;
59575                         duk_tval *tv2;
59576
59577                         DUK_DDD(DUK_DDDPRINT("create new data property"));
59578
59579                         DUK_ASSERT(!has_set);
59580                         DUK_ASSERT(!has_get);
59581
59582                         new_flags = 0;  /* defaults, E5 Section 8.6.1, Table 7 */
59583                         if (has_writable && is_writable) {
59584                                 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
59585                         }
59586                         if (has_enumerable && is_enumerable) {
59587                                 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
59588                         }
59589                         if (has_configurable && is_configurable) {
59590                                 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
59591                         }
59592                         if (has_value) {
59593                                 duk_tval *tv_tmp = duk_require_tval(thr, idx_value);
59594                                 DUK_TVAL_SET_TVAL(&tv, tv_tmp);
59595                         } else {
59596                                 DUK_TVAL_SET_UNDEFINED(&tv);  /* default value */
59597                         }
59598
59599                         if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
59600                                 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
59601 #if 0
59602                                         DUK_DDD(DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part"));
59603                                         /* may become sparse...*/
59604 #endif
59605                                         /* XXX: handling for array part missing now; this doesn't affect
59606                                          * compliance but causes array entry writes using defineProperty()
59607                                          * to always abandon array part.
59608                                          */
59609                                 }
59610                                 DUK_DDD(DUK_DDDPRINT("new data property cannot go to array part, abandon array"));
59611                                 duk__abandon_array_checked(thr, obj);
59612                                 /* fall through */
59613                         }
59614
59615                         /* write to entry part */
59616                         e_idx = duk__hobject_alloc_entry_checked(thr, obj, key);
59617                         DUK_ASSERT(e_idx >= 0);
59618                         tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
59619                         DUK_TVAL_SET_TVAL(tv2, &tv);
59620                         DUK_TVAL_INCREF(thr, tv2);
59621
59622                         DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
59623                         goto success_exotics;
59624                 }
59625                 DUK_UNREACHABLE();
59626         }
59627
59628         /* we currently assume virtual properties are not configurable (as none of them are) */
59629         DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE));
59630
59631         /* [obj key desc value get set curr_value] */
59632
59633         /*
59634          *  Property already exists.  Steps 5-6 detect whether any changes need
59635          *  to be made.
59636          */
59637
59638         if (has_enumerable) {
59639                 if (is_enumerable) {
59640                         if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) {
59641                                 goto need_check;
59642                         }
59643                 } else {
59644                         if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
59645                                 goto need_check;
59646                         }
59647                 }
59648         }
59649         if (has_configurable) {
59650                 if (is_configurable) {
59651                         if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
59652                                 goto need_check;
59653                         }
59654                 } else {
59655                         if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
59656                                 goto need_check;
59657                         }
59658                 }
59659         }
59660         if (has_value) {
59661                 duk_tval *tmp1;
59662                 duk_tval *tmp2;
59663
59664                 /* attempt to change from accessor to data property */
59665                 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
59666                         goto need_check;
59667                 }
59668
59669                 tmp1 = duk_require_tval(thr, -1);         /* curr value */
59670                 tmp2 = duk_require_tval(thr, idx_value);  /* new value */
59671                 if (!duk_js_samevalue(tmp1, tmp2)) {
59672                         goto need_check;
59673                 }
59674         }
59675         if (has_writable) {
59676                 /* attempt to change from accessor to data property */
59677                 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
59678                         goto need_check;
59679                 }
59680
59681                 if (is_writable) {
59682                         if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
59683                                 goto need_check;
59684                         }
59685                 } else {
59686                         if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) {
59687                                 goto need_check;
59688                         }
59689                 }
59690         }
59691         if (has_set) {
59692                 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
59693                         if (set != curr.set) {
59694                                 goto need_check;
59695                         }
59696                 } else {
59697                         goto need_check;
59698                 }
59699         }
59700         if (has_get) {
59701                 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
59702                         if (get != curr.get) {
59703                                 goto need_check;
59704                         }
59705                 } else {
59706                         goto need_check;
59707                 }
59708         }
59709
59710         /* property exists, either 'desc' is empty, or all values
59711          * match (SameValue)
59712          */
59713         goto success_no_exotics;
59714
59715  need_check:
59716
59717         /*
59718          *  Some change(s) need to be made.  Steps 7-11.
59719          */
59720
59721         /* shared checks for all descriptor types */
59722         if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
59723                 if (has_configurable && is_configurable) {
59724                         goto fail_not_configurable;
59725                 }
59726                 if (has_enumerable) {
59727                         if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
59728                                 if (!is_enumerable) {
59729                                         goto fail_not_configurable;
59730                                 }
59731                         } else {
59732                                 if (is_enumerable) {
59733                                         goto fail_not_configurable;
59734                                 }
59735                         }
59736                 }
59737         }
59738
59739         /* Virtual properties don't have backing so they can't mostly be
59740          * edited.  Some virtual properties are, however, writable: for
59741          * example, virtual index properties of buffer objects and Array
59742          * instance .length.  These are not configurable so the checks
59743          * above mostly cover attempts to change them, except when the
59744          * duk_def_prop() call is used with DUK_DEFPROP_FORCE; even in
59745          * that case we can't forcibly change the property attributes
59746          * because they don't have concrete backing.
59747          */
59748
59749         /* XXX: for ROM objects too it'd be best if value modify was
59750          * allowed if the value matches SameValue.
59751          */
59752         /* Reject attempt to change a read-only object. */
59753 #if defined(DUK_USE_ROM_OBJECTS)
59754         if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
59755                 DUK_DD(DUK_DDPRINT("attempt to define property on read-only target object"));
59756                 goto fail_not_configurable;
59757         }
59758 #endif
59759
59760         /* descriptor type specific checks */
59761         if (has_set || has_get) {
59762                 /* IsAccessorDescriptor(desc) == true */
59763                 DUK_ASSERT(!has_writable);
59764                 DUK_ASSERT(!has_value);
59765
59766                 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
59767                         /* curr and desc are accessors */
59768                         if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
59769                                 if (has_set && set != curr.set) {
59770                                         goto fail_not_configurable;
59771                                 }
59772                                 if (has_get && get != curr.get) {
59773                                         goto fail_not_configurable;
59774                                 }
59775                         }
59776                 } else {
59777                         duk_bool_t rc;
59778                         duk_tval *tv1;
59779
59780                         /* curr is data, desc is accessor */
59781                         if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
59782                                 goto fail_not_configurable;
59783                         }
59784
59785                         DUK_DDD(DUK_DDDPRINT("convert property to accessor property"));
59786                         if (curr.a_idx >= 0) {
59787                                 DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup"));
59788                                 duk__abandon_array_checked(thr, obj);
59789                                 duk_pop_unsafe(thr);  /* remove old value */
59790                                 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
59791                                 DUK_UNREF(rc);
59792                                 DUK_ASSERT(rc != 0);
59793                                 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
59794                         }
59795                         if (curr.e_idx < 0) {
59796                                 DUK_ASSERT(curr.a_idx < 0 && curr.e_idx < 0);
59797                                 goto fail_virtual;  /* safeguard for virtual property */
59798                         }
59799
59800                         DUK_ASSERT(curr.e_idx >= 0);
59801                         DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
59802
59803                         tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
59804                         DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv1);  /* XXX: just decref */
59805
59806                         DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
59807                         DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
59808                         DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
59809                         DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, curr.e_idx);
59810
59811                         DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx",
59812                                              (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
59813                         /* Update curr.flags; faster than a re-lookup. */
59814                         curr.flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
59815                         curr.flags |= DUK_PROPDESC_FLAG_ACCESSOR;
59816                 }
59817         } else if (has_value || has_writable) {
59818                 /* IsDataDescriptor(desc) == true */
59819                 DUK_ASSERT(!has_set);
59820                 DUK_ASSERT(!has_get);
59821
59822                 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
59823                         duk_hobject *tmp;
59824
59825                         /* curr is accessor, desc is data */
59826                         if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
59827                                 goto fail_not_configurable;
59828                         }
59829
59830                         /* curr is accessor -> cannot be in array part. */
59831                         DUK_ASSERT(curr.a_idx < 0);
59832                         if (curr.e_idx < 0) {
59833                                 goto fail_virtual;  /* safeguard; no virtual accessors now */
59834                         }
59835
59836                         DUK_DDD(DUK_DDDPRINT("convert property to data property"));
59837
59838                         DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
59839                         tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
59840                         DUK_UNREF(tmp);
59841                         DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
59842                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
59843                         tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
59844                         DUK_UNREF(tmp);
59845                         DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
59846                         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
59847
59848                         DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
59849                         DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
59850                         DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(thr->heap, obj, curr.e_idx);
59851
59852                         DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx",
59853                                              (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
59854
59855                         /* Update curr.flags; faster than a re-lookup. */
59856                         curr.flags &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ACCESSOR);
59857                 } else {
59858                         /* curr and desc are data */
59859                         if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
59860                                 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) {
59861                                         goto fail_not_configurable;
59862                                 }
59863                                 /* Note: changing from writable to non-writable is OK */
59864                                 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
59865                                         duk_tval *tmp1 = duk_require_tval(thr, -1);         /* curr value */
59866                                         duk_tval *tmp2 = duk_require_tval(thr, idx_value);  /* new value */
59867                                         if (!duk_js_samevalue(tmp1, tmp2)) {
59868                                                 goto fail_not_configurable;
59869                                         }
59870                                 }
59871                         }
59872                 }
59873         } else {
59874                 /* IsGenericDescriptor(desc) == true; this means in practice that 'desc'
59875                  * only has [[Enumerable]] or [[Configurable]] flag updates, which are
59876                  * allowed at this point.
59877                  */
59878
59879                 DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set);
59880         }
59881
59882         /*
59883          *  Start doing property attributes updates.  Steps 12-13.
59884          *
59885          *  Start by computing new attribute flags without writing yet.
59886          *  Property type conversion is done above if necessary.
59887          */
59888
59889         new_flags = curr.flags;
59890
59891         if (has_enumerable) {
59892                 if (is_enumerable) {
59893                         new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
59894                 } else {
59895                         new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE;
59896                 }
59897         }
59898         if (has_configurable) {
59899                 if (is_configurable) {
59900                         new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
59901                 } else {
59902                         new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
59903                 }
59904         }
59905         if (has_writable) {
59906                 if (is_writable) {
59907                         new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
59908                 } else {
59909                         new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
59910                 }
59911         }
59912
59913         /* XXX: write protect after flag? -> any chance of handling it here? */
59914
59915         DUK_DDD(DUK_DDDPRINT("new flags that we want to write: 0x%02lx",
59916                              (unsigned long) new_flags));
59917
59918         /*
59919          *  Check whether we need to abandon an array part (if it exists)
59920          */
59921
59922         if (curr.a_idx >= 0) {
59923                 duk_bool_t rc;
59924
59925                 DUK_ASSERT(curr.e_idx < 0);
59926
59927                 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
59928                         duk_tval *tv1, *tv2;
59929
59930                         DUK_DDD(DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place"));
59931
59932                         DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC);  /* must have been, since in array part */
59933                         DUK_ASSERT(!has_set);
59934                         DUK_ASSERT(!has_get);
59935                         DUK_ASSERT(idx_value >= 0);  /* must be: if attributes match and we get here the value must differ (otherwise no change) */
59936
59937                         tv2 = duk_require_tval(thr, idx_value);
59938                         tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx);
59939                         DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2);  /* side effects; may invalidate a_idx */
59940                         goto success_exotics;
59941                 }
59942
59943                 DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup"));
59944                 duk__abandon_array_checked(thr, obj);
59945                 duk_pop_unsafe(thr);  /* remove old value */
59946                 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
59947                 DUK_UNREF(rc);
59948                 DUK_ASSERT(rc != 0);
59949                 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
59950         }
59951
59952         DUK_DDD(DUK_DDDPRINT("updating existing property in entry part"));
59953
59954         /* Array case is handled comprehensively above: either in entry
59955          * part or a virtual property.
59956          */
59957         DUK_ASSERT(curr.a_idx < 0);
59958
59959         DUK_DDD(DUK_DDDPRINT("update existing property attributes"));
59960         if (curr.e_idx >= 0) {
59961                 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags);
59962         } else {
59963                 /* For Array .length the only allowed transition is for .length
59964                  * to become non-writable.
59965                  */
59966                 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
59967                         duk_harray *a;
59968                         a = (duk_harray *) obj;
59969                         DUK_DD(DUK_DDPRINT("Object.defineProperty() attribute update for duk_harray .length -> %02lx", (unsigned long) new_flags));
59970                         DUK_ASSERT_HARRAY_VALID(a);
59971                         if ((new_flags & DUK_PROPDESC_FLAGS_EC) != (curr.flags & DUK_PROPDESC_FLAGS_EC)) {
59972                                 DUK_D(DUK_DPRINT("Object.defineProperty() attempt to change virtual array .length enumerable or configurable attribute, fail"));
59973                                 goto fail_virtual;
59974                         }
59975                         if (new_flags & DUK_PROPDESC_FLAG_WRITABLE) {
59976                                 DUK_HARRAY_SET_LENGTH_WRITABLE(a);
59977                         } else {
59978                                 DUK_HARRAY_SET_LENGTH_NONWRITABLE(a);
59979                         }
59980                 }
59981         }
59982
59983         if (has_set) {
59984                 duk_hobject *tmp;
59985
59986                 /* Virtual properties are non-configurable but with a 'force'
59987                  * flag we might come here so check explicitly for virtual.
59988                  */
59989                 if (curr.e_idx < 0) {
59990                         goto fail_virtual;
59991                 }
59992
59993                 DUK_DDD(DUK_DDDPRINT("update existing property setter"));
59994                 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
59995
59996                 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
59997                 DUK_UNREF(tmp);
59998                 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set);
59999                 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
60000                 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);  /* side effects; may invalidate e_idx */
60001         }
60002         if (has_get) {
60003                 duk_hobject *tmp;
60004
60005                 if (curr.e_idx < 0) {
60006                         goto fail_virtual;
60007                 }
60008
60009                 DUK_DDD(DUK_DDDPRINT("update existing property getter"));
60010                 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
60011
60012                 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
60013                 DUK_UNREF(tmp);
60014                 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get);
60015                 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
60016                 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);  /* side effects; may invalidate e_idx */
60017         }
60018         if (has_value) {
60019                 duk_tval *tv1, *tv2;
60020
60021                 DUK_DDD(DUK_DDDPRINT("update existing property value"));
60022
60023                 if (curr.e_idx >= 0) {
60024                         DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
60025                         tv2 = duk_require_tval(thr, idx_value);
60026                         tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
60027                         DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2);  /* side effects; may invalidate e_idx */
60028                 } else {
60029                         DUK_ASSERT(curr.a_idx < 0);  /* array part case handled comprehensively previously */
60030
60031                         DUK_DD(DUK_DDPRINT("Object.defineProperty(), value update for virtual property"));
60032                         /* XXX: Uint8Array and other typed array virtual writes not currently
60033                          * handled.
60034                          */
60035                         if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
60036                                 duk_harray *a;
60037                                 a = (duk_harray *) obj;
60038                                 DUK_DD(DUK_DDPRINT("Object.defineProperty() value update for duk_harray .length -> %ld", (long) arrlen_new_len));
60039                                 DUK_ASSERT_HARRAY_VALID(a);
60040                                 a->length = arrlen_new_len;
60041                         } else {
60042                                 goto fail_virtual;  /* should not happen */
60043                         }
60044                 }
60045         }
60046
60047         /*
60048          *  Standard algorithm succeeded without errors, check for exotic post-behaviors.
60049          *
60050          *  Arguments exotic behavior in E5 Section 10.6 occurs after the standard
60051          *  [[DefineOwnProperty]] has completed successfully.
60052          *
60053          *  Array exotic behavior in E5 Section 15.4.5.1 is implemented partly
60054          *  prior to the default [[DefineOwnProperty]], but:
60055          *    - for an array index key (e.g. "10") the final 'length' update occurs here
60056          *    - for 'length' key the element deletion and 'length' update occurs here
60057          */
60058
60059  success_exotics:
60060
60061         /* curr.a_idx or curr.e_idx may have been invalidated by side effects
60062          * above.
60063          */
60064
60065         /* [obj key desc value get set curr_value] */
60066
60067         if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
60068                 duk_harray *a;
60069
60070                 a = (duk_harray *) obj;
60071                 DUK_ASSERT_HARRAY_VALID(a);
60072
60073                 if (arridx_new_array_length > 0) {
60074                         /*
60075                          *  Note: zero works as a "no update" marker because the new length
60076                          *  can never be zero after a new property is written.
60077                          */
60078
60079                         /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */
60080
60081                         DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld",
60082                                              (long) arridx_new_array_length));
60083
60084                         a->length = arridx_new_array_length;
60085                 }
60086
60087                 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) {
60088                         /*
60089                          *  E5 Section 15.4.5.1, steps 3.k - 3.n.  The order at the end combines
60090                          *  the error case 3.l.iii and the success case 3.m-3.n.
60091                          */
60092
60093                         /* XXX: investigate whether write protect can be handled above, if we
60094                          * just update length here while ignoring its protected status
60095                          */
60096
60097                         duk_uint32_t result_len;
60098                         duk_bool_t rc;
60099
60100                         DUK_DDD(DUK_DDDPRINT("defineProperty successful, key is 'length', exotic array behavior, "
60101                                              "doing array element deletion and length update"));
60102
60103                         rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, force_flag, &result_len);
60104
60105                         /* update length (curr points to length, and we assume it's still valid) */
60106                         DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len);
60107
60108                         a->length = result_len;
60109
60110                         if (pending_write_protect) {
60111                                 DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)"));
60112                                 DUK_HARRAY_SET_LENGTH_NONWRITABLE(a);
60113                         }
60114
60115                         /* XXX: shrink array allocation or entries compaction here? */
60116                         if (!rc) {
60117                                 DUK_DD(DUK_DDPRINT("array length write only partially successful"));
60118                                 goto fail_not_configurable;
60119                         }
60120                 }
60121         } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
60122                 duk_hobject *map;
60123                 duk_hobject *varenv;
60124
60125                 DUK_ASSERT(arridx_new_array_length == 0);
60126                 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));  /* traits are separate; in particular, arguments not an array */
60127
60128                 map = NULL;
60129                 varenv = NULL;
60130                 if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) {
60131                         goto success_no_exotics;
60132                 }
60133                 DUK_ASSERT(map != NULL);
60134                 DUK_ASSERT(varenv != NULL);
60135
60136                 /* [obj key desc value get set curr_value varname] */
60137
60138                 if (has_set || has_get) {
60139                         /* = IsAccessorDescriptor(Desc) */
60140                         DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' "
60141                                              "changed to an accessor, delete arguments binding"));
60142
60143                         (void) duk_hobject_delprop_raw(thr, map, key, 0);  /* ignore result */
60144                 } else {
60145                         /* Note: this order matters (final value before deleting map entry must be done) */
60146                         DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
60147                                              "check for value update / binding deletion"));
60148
60149                         if (has_value) {
60150                                 duk_hstring *varname;
60151
60152                                 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
60153                                                      "update bound value (variable/argument)"));
60154
60155                                 varname = duk_require_hstring(thr, -1);
60156                                 DUK_ASSERT(varname != NULL);
60157
60158                                 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
60159                                                      "key=%!O, varname=%!O, value=%!T",
60160                                                      (duk_heaphdr *) key,
60161                                                      (duk_heaphdr *) varname,
60162                                                      (duk_tval *) duk_require_tval(thr, idx_value)));
60163
60164                                 /* strict flag for putvar comes from our caller (currently: fixed) */
60165                                 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(thr, idx_value), 1 /*throw_flag*/);
60166                         }
60167                         if (has_writable && !is_writable) {
60168                                 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
60169                                                      "changed to non-writable, delete arguments binding"));
60170
60171                                 (void) duk_hobject_delprop_raw(thr, map, key, 0);  /* ignore result */
60172                         }
60173                 }
60174
60175                 /* 'varname' is in stack in this else branch, leaving an unbalanced stack below,
60176                  * but this doesn't matter now.
60177                  */
60178         }
60179
60180  success_no_exotics:
60181         /* Some code paths use NORZ macros for simplicity, ensure refzero
60182          * handling is completed.
60183          */
60184         DUK_REFZERO_CHECK_SLOW(thr);
60185         return 1;
60186
60187  fail_not_extensible:
60188         if (throw_flag) {
60189                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
60190                 DUK_WO_NORETURN(return 0;);
60191         }
60192         return 0;
60193
60194  fail_virtual:  /* just use the same "not configurable" error message" */
60195  fail_not_configurable:
60196         if (throw_flag) {
60197                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
60198                 DUK_WO_NORETURN(return 0;);
60199         }
60200         return 0;
60201 }
60202
60203 /*
60204  *  Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
60205  */
60206
60207 DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_hthread *thr, duk_small_uint_t required_desc_flags) {
60208         duk_hstring *h_v;
60209         duk_hobject *h_obj;
60210         duk_propdesc desc;
60211         duk_bool_t ret;
60212
60213         /* coercion order matters */
60214         h_v = duk_to_hstring_acceptsymbol(thr, 0);
60215         DUK_ASSERT(h_v != NULL);
60216
60217         h_obj = duk_push_this_coercible_to_object(thr);
60218         DUK_ASSERT(h_obj != NULL);
60219
60220         ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/);  /* don't push value */
60221
60222         duk_push_boolean(thr, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
60223         return 1;
60224 }
60225
60226 /*
60227  *  Object.seal() and Object.freeze()  (E5 Sections 15.2.3.8 and 15.2.3.9)
60228  *
60229  *  Since the algorithms are similar, a helper provides both functions.
60230  *  Freezing is essentially sealing + making plain properties non-writable.
60231  *
60232  *  Note: virtual (non-concrete) properties which are non-configurable but
60233  *  writable would pose some problems, but such properties do not currently
60234  *  exist (all virtual properties are non-configurable and non-writable).
60235  *  If they did exist, the non-configurability does NOT prevent them from
60236  *  becoming non-writable.  However, this change should be recorded somehow
60237  *  so that it would turn up (e.g. when getting the property descriptor),
60238  *  requiring some additional flags in the object.
60239  */
60240
60241 DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze) {
60242         duk_uint_fast32_t i;
60243
60244         DUK_ASSERT(thr != NULL);
60245         DUK_ASSERT(thr->heap != NULL);
60246         DUK_ASSERT(obj != NULL);
60247
60248         DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
60249
60250 #if defined(DUK_USE_ROM_OBJECTS)
60251         if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
60252                 DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject"));
60253                 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
60254                 DUK_WO_NORETURN(return;);
60255         }
60256 #endif
60257
60258         /*
60259          *  Abandon array part because all properties must become non-configurable.
60260          *  Note that this is now done regardless of whether this is always the case
60261          *  (skips check, but performance problem if caller would do this many times
60262          *  for the same object; not likely).
60263          */
60264
60265         duk__abandon_array_checked(thr, obj);
60266         DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) == 0);
60267
60268         for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
60269                 duk_uint8_t *fp;
60270
60271                 /* since duk__abandon_array_checked() causes a resize, there should be no gaps in keys */
60272                 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != NULL);
60273
60274                 /* avoid multiple computations of flags address; bypasses macros */
60275                 fp = DUK_HOBJECT_E_GET_FLAGS_PTR(thr->heap, obj, i);
60276                 if (is_freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) {
60277                         *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE);
60278                 } else {
60279                         *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
60280                 }
60281         }
60282
60283         DUK_HOBJECT_CLEAR_EXTENSIBLE(obj);
60284
60285         /* no need to compact since we already did that in duk__abandon_array_checked()
60286          * (regardless of whether an array part existed or not.
60287          */
60288
60289         return;
60290 }
60291
60292 /*
60293  *  Object.isSealed() and Object.isFrozen()  (E5 Sections 15.2.3.11, 15.2.3.13)
60294  *
60295  *  Since the algorithms are similar, a helper provides both functions.
60296  *  Freezing is essentially sealing + making plain properties non-writable.
60297  *
60298  *  Note: all virtual (non-concrete) properties are currently non-configurable
60299  *  and non-writable (and there are no accessor virtual properties), so they don't
60300  *  need to be considered here now.
60301  */
60302
60303 DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) {
60304         duk_uint_fast32_t i;
60305
60306         DUK_ASSERT(obj != NULL);
60307         DUK_UNREF(thr);
60308
60309         /* Note: no allocation pressure, no need to check refcounts etc */
60310
60311         /* must not be extensible */
60312         if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
60313                 return 0;
60314         }
60315
60316         /* all virtual properties are non-configurable and non-writable */
60317
60318         /* entry part must not contain any configurable properties, or
60319          * writable properties (if is_frozen).
60320          */
60321         for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
60322                 duk_small_uint_t flags;
60323
60324                 if (!DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i)) {
60325                         continue;
60326                 }
60327
60328                 /* avoid multiple computations of flags address; bypasses macros */
60329                 flags = (duk_small_uint_t) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
60330
60331                 if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
60332                         return 0;
60333                 }
60334                 if (is_frozen &&
60335                     !(flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
60336                     (flags & DUK_PROPDESC_FLAG_WRITABLE)) {
60337                         return 0;
60338                 }
60339         }
60340
60341         /* array part must not contain any non-unused properties, as they would
60342          * be configurable and writable.
60343          */
60344         for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
60345                 duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
60346                 if (!DUK_TVAL_IS_UNUSED(tv)) {
60347                         return 0;
60348                 }
60349         }
60350
60351         return 1;
60352 }
60353
60354 /*
60355  *  Object.preventExtensions() and Object.isExtensible()  (E5 Sections 15.2.3.10, 15.2.3.13)
60356  *
60357  *  Not needed, implemented by macros DUK_HOBJECT_{HAS,CLEAR,SET}_EXTENSIBLE
60358  *  and the Object built-in bindings.
60359  */
60360
60361 /* automatic undefs */
60362 #undef DUK__HASH_DELETED
60363 #undef DUK__HASH_UNUSED
60364 #undef DUK__NO_ARRAY_INDEX
60365 #undef DUK__VALSTACK_PROXY_LOOKUP
60366 #undef DUK__VALSTACK_SPACE
60367 #line 1 "duk_hstring_misc.c"
60368 /*
60369  *  Misc support functions
60370  */
60371
60372 /* #include duk_internal.h -> already included */
60373
60374 /*
60375  *  duk_hstring charCodeAt, with and without surrogate awareness
60376  */
60377
60378 DUK_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) {
60379         duk_uint32_t boff;
60380         const duk_uint8_t *p, *p_start, *p_end;
60381         duk_ucodepoint_t cp1;
60382         duk_ucodepoint_t cp2;
60383
60384         /* Caller must check character offset to be inside the string. */
60385         DUK_ASSERT(thr != NULL);
60386         DUK_ASSERT(h != NULL);
60387         DUK_ASSERT_DISABLE(pos >= 0);  /* unsigned */
60388         DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));
60389
60390         boff = (duk_uint32_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
60391         DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O",
60392                              (long) pos, (long) boff, (duk_heaphdr *) h));
60393         DUK_ASSERT_DISABLE(boff >= 0);
60394         DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h));
60395
60396         p_start = DUK_HSTRING_GET_DATA(h);
60397         p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
60398         p = p_start + boff;
60399         DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p",
60400                              (const void *) p_start, (const void *) p_end,
60401                              (const void *) p));
60402
60403         /* For invalid UTF-8 (never happens for standard ECMAScript strings)
60404          * return U+FFFD replacement character.
60405          */
60406         if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp1)) {
60407                 if (surrogate_aware && cp1 >= 0xd800UL && cp1 <= 0xdbffUL) {
60408                         /* The decode helper is memory safe even if 'cp1' was
60409                          * decoded at the end of the string and 'p' is no longer
60410                          * within string memory range.
60411                          */
60412                         cp2 = 0;  /* If call fails, this is left untouched and won't match cp2 check. */
60413                         (void) duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp2);
60414                         if (cp2 >= 0xdc00UL && cp2 <= 0xdfffUL) {
60415                                 cp1 = (duk_ucodepoint_t) (((cp1 - 0xd800UL) << 10) + (cp2 - 0xdc00UL) + 0x10000UL);
60416                         }
60417                 }
60418         } else {
60419                 cp1 = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
60420         }
60421
60422         return cp1;
60423 }
60424
60425 /*
60426  *  duk_hstring charlen, when lazy charlen disabled
60427  */
60428
60429 #if !defined(DUK_USE_HSTRING_LAZY_CLEN)
60430 #if !defined(DUK_USE_HSTRING_CLEN)
60431 #error non-lazy duk_hstring charlen but DUK_USE_HSTRING_CLEN not set
60432 #endif
60433 DUK_INTERNAL void duk_hstring_init_charlen(duk_hstring *h) {
60434         duk_uint32_t clen;
60435
60436         DUK_ASSERT(h != NULL);
60437         DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(h));
60438         DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
60439
60440         clen = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
60441 #if defined(DUK_USE_STRLEN16)
60442         DUK_ASSERT(clen <= 0xffffUL);  /* Bytelength checked during interning. */
60443         h->clen16 = (duk_uint16_t) clen;
60444 #else
60445         h->clen = (duk_uint32_t) clen;
60446 #endif
60447         if (DUK_LIKELY(clen == DUK_HSTRING_GET_BYTELEN(h))) {
60448                 DUK_HSTRING_SET_ASCII(h);
60449         }
60450 }
60451
60452 DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
60453 #if defined(DUK_USE_STRLEN16)
60454         return h->clen16;
60455 #else
60456         return h->clen;
60457 #endif
60458 }
60459 #endif  /* !DUK_USE_HSTRING_LAZY_CLEN */
60460
60461 /*
60462  *  duk_hstring charlen, when lazy charlen enabled
60463  */
60464
60465 #if defined(DUK_USE_HSTRING_LAZY_CLEN)
60466 #if defined(DUK_USE_HSTRING_CLEN)
60467 DUK_LOCAL DUK_COLD duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) {
60468         duk_size_t res;
60469
60470         DUK_ASSERT(h->clen == 0);  /* Checked by caller. */
60471
60472 #if defined(DUK_USE_ROM_STRINGS)
60473         /* ROM strings have precomputed clen, but if the computed clen is zero
60474          * we can still come here and can't write anything.
60475          */
60476         if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) {
60477                 return 0;
60478         }
60479 #endif
60480
60481         res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
60482 #if defined(DUK_USE_STRLEN16)
60483         DUK_ASSERT(res <= 0xffffUL);  /* Bytelength checked during interning. */
60484         h->clen16 = (duk_uint16_t) res;
60485 #else
60486         h->clen = (duk_uint32_t) res;
60487 #endif
60488         if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) {
60489                 DUK_HSTRING_SET_ASCII(h);
60490         }
60491         return res;
60492 }
60493 #else  /* DUK_USE_HSTRING_CLEN */
60494 DUK_LOCAL duk_size_t duk__hstring_get_charlen_slowpath(duk_hstring *h) {
60495         if (DUK_LIKELY(DUK_HSTRING_HAS_ASCII(h))) {
60496                 /* Most practical strings will go here. */
60497                 return DUK_HSTRING_GET_BYTELEN(h);
60498         } else {
60499                 /* ASCII flag is lazy, so set it here. */
60500                 duk_size_t res;
60501
60502                 /* XXX: here we could use the strcache to speed up the
60503                  * computation (matters for 'i < str.length' loops).
60504                  */
60505
60506                 res = duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
60507
60508 #if defined(DUK_USE_ROM_STRINGS)
60509                 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) {
60510                         /* For ROM strings, can't write anything; ASCII flag
60511                          * is preset so we don't need to update it.
60512                          */
60513                         return res;
60514                 }
60515 #endif
60516                 if (DUK_LIKELY(res == DUK_HSTRING_GET_BYTELEN(h))) {
60517                         DUK_HSTRING_SET_ASCII(h);
60518                 }
60519                 return res;
60520         }
60521 }
60522 #endif  /* DUK_USE_HSTRING_CLEN */
60523
60524 #if defined(DUK_USE_HSTRING_CLEN)
60525 DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
60526 #if defined(DUK_USE_STRLEN16)
60527         if (DUK_LIKELY(h->clen16 != 0)) {
60528                 return h->clen16;
60529         }
60530 #else
60531         if (DUK_LIKELY(h->clen != 0)) {
60532                 return h->clen;
60533         }
60534 #endif
60535         return duk__hstring_get_charlen_slowpath(h);
60536 }
60537 #else  /* DUK_USE_HSTRING_CLEN */
60538 DUK_INTERNAL DUK_HOT duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
60539         /* Always use slow path. */
60540         return duk__hstring_get_charlen_slowpath(h);
60541 }
60542 #endif  /* DUK_USE_HSTRING_CLEN */
60543 #endif  /* DUK_USE_HSTRING_LAZY_CLEN */
60544
60545 /*
60546  *  Compare duk_hstring to an ASCII cstring.
60547  */
60548
60549 DUK_INTERNAL duk_bool_t duk_hstring_equals_ascii_cstring(duk_hstring *h, const char *cstr) {
60550         duk_size_t len;
60551
60552         DUK_ASSERT(h != NULL);
60553         DUK_ASSERT(cstr != NULL);
60554
60555         len = DUK_STRLEN(cstr);
60556         if (len != DUK_HSTRING_GET_BYTELEN(h)) {
60557                 return 0;
60558         }
60559         if (duk_memcmp((const void *) cstr, (const void *) DUK_HSTRING_GET_DATA(h), len) == 0) {
60560                 return 1;
60561         }
60562         return 0;
60563 }
60564 #line 1 "duk_hthread_alloc.c"
60565 /*
60566  *  duk_hthread allocation and freeing.
60567  */
60568
60569 /* #include duk_internal.h -> already included */
60570
60571 /*
60572  *  Allocate initial stacks for a thread.  Note that 'thr' must be reachable
60573  *  as a garbage collection may be triggered by the allocation attempts.
60574  *  Returns zero (without leaking memory) if init fails.
60575  */
60576
60577 DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) {
60578         duk_size_t alloc_size;
60579         duk_size_t i;
60580
60581         DUK_ASSERT(heap != NULL);
60582         DUK_ASSERT(thr != NULL);
60583         DUK_ASSERT(thr->valstack == NULL);
60584         DUK_ASSERT(thr->valstack_end == NULL);
60585         DUK_ASSERT(thr->valstack_alloc_end == NULL);
60586         DUK_ASSERT(thr->valstack_bottom == NULL);
60587         DUK_ASSERT(thr->valstack_top == NULL);
60588         DUK_ASSERT(thr->callstack_curr == NULL);
60589
60590         /* valstack */
60591         DUK_ASSERT(DUK_VALSTACK_API_ENTRY_MINIMUM <= DUK_VALSTACK_INITIAL_SIZE);
60592         alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
60593         thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
60594         if (!thr->valstack) {
60595                 goto fail;
60596         }
60597         duk_memzero(thr->valstack, alloc_size);
60598         thr->valstack_end = thr->valstack + DUK_VALSTACK_API_ENTRY_MINIMUM;
60599         thr->valstack_alloc_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
60600         thr->valstack_bottom = thr->valstack;
60601         thr->valstack_top = thr->valstack;
60602
60603         for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) {
60604                 DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]);
60605         }
60606
60607         return 1;
60608
60609  fail:
60610         DUK_FREE(heap, thr->valstack);
60611         DUK_ASSERT(thr->callstack_curr == NULL);
60612
60613         thr->valstack = NULL;
60614         return 0;
60615 }
60616
60617 /* For indirect allocs. */
60618
60619 DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) {
60620         duk_hthread *thr = (duk_hthread *) ud;
60621         DUK_UNREF(heap);
60622         return (void *) thr->valstack;
60623 }
60624 #line 1 "duk_hthread_builtins.c"
60625 /*
60626  *  Initialize built-in objects.  Current thread must have a valstack
60627  *  and initialization errors may longjmp, so a setjmp() catch point
60628  *  must exist.
60629  */
60630
60631 /* #include duk_internal.h -> already included */
60632
60633 /*
60634  *  Encoding constants, must match genbuiltins.py
60635  */
60636
60637 #define DUK__PROP_FLAGS_BITS             3
60638 #define DUK__LENGTH_PROP_BITS            3
60639 #define DUK__NARGS_BITS                  3
60640 #define DUK__PROP_TYPE_BITS              3
60641
60642 #define DUK__NARGS_VARARGS_MARKER        0x07
60643
60644 #define DUK__PROP_TYPE_DOUBLE            0
60645 #define DUK__PROP_TYPE_STRING            1
60646 #define DUK__PROP_TYPE_STRIDX            2
60647 #define DUK__PROP_TYPE_BUILTIN           3
60648 #define DUK__PROP_TYPE_UNDEFINED         4
60649 #define DUK__PROP_TYPE_BOOLEAN_TRUE      5
60650 #define DUK__PROP_TYPE_BOOLEAN_FALSE     6
60651 #define DUK__PROP_TYPE_ACCESSOR          7
60652
60653 /*
60654  *  Create built-in objects by parsing an init bitstream generated
60655  *  by genbuiltins.py.
60656  */
60657
60658 #if defined(DUK_USE_ROM_OBJECTS)
60659 #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
60660 DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
60661         duk_hobject *h_global;
60662 #if defined(DUK_USE_ROM_GLOBAL_CLONE)
60663         duk_hobject *h_oldglobal;
60664         duk_uint8_t *props;
60665         duk_size_t alloc_size;
60666 #endif
60667         duk_hobject *h_objenv;
60668
60669         /* XXX: refactor into internal helper, duk_clone_hobject() */
60670
60671 #if defined(DUK_USE_ROM_GLOBAL_INHERIT)
60672         /* Inherit from ROM-based global object: less RAM usage, less transparent. */
60673         h_global = duk_push_object_helper(thr,
60674                                           DUK_HOBJECT_FLAG_EXTENSIBLE |
60675                                           DUK_HOBJECT_FLAG_FASTREFS |
60676                                           DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
60677                                           DUK_BIDX_GLOBAL);
60678         DUK_ASSERT(h_global != NULL);
60679 #elif defined(DUK_USE_ROM_GLOBAL_CLONE)
60680         /* Clone the properties of the ROM-based global object to create a
60681          * fully RAM-based global object.  Uses more memory than the inherit
60682          * model but more compliant.
60683          */
60684         h_global = duk_push_object_helper(thr,
60685                                           DUK_HOBJECT_FLAG_EXTENSIBLE |
60686                                           DUK_HOBJECT_FLAG_FASTREFS |
60687                                           DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
60688                                           DUK_BIDX_OBJECT_PROTOTYPE);
60689         DUK_ASSERT(h_global != NULL);
60690         h_oldglobal = thr->builtins[DUK_BIDX_GLOBAL];
60691         DUK_ASSERT(h_oldglobal != NULL);
60692
60693         /* Copy the property table verbatim; this handles attributes etc.
60694          * For ROM objects it's not necessary (or possible) to update
60695          * refcounts so leave them as is.
60696          */
60697         alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h_oldglobal);
60698         DUK_ASSERT(alloc_size > 0);
60699         props = DUK_ALLOC_CHECKED(thr, alloc_size);
60700         DUK_ASSERT(props != NULL);
60701         DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal) != NULL);
60702         duk_memcpy((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h_oldglobal), alloc_size);
60703
60704         /* XXX: keep property attributes or tweak them here?
60705          * Properties will now be non-configurable even when they're
60706          * normally configurable for the global object.
60707          */
60708
60709         DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h_global) == NULL);
60710         DUK_HOBJECT_SET_PROPS(thr->heap, h_global, props);
60711         DUK_HOBJECT_SET_ESIZE(h_global, DUK_HOBJECT_GET_ESIZE(h_oldglobal));
60712         DUK_HOBJECT_SET_ENEXT(h_global, DUK_HOBJECT_GET_ENEXT(h_oldglobal));
60713         DUK_HOBJECT_SET_ASIZE(h_global, DUK_HOBJECT_GET_ASIZE(h_oldglobal));
60714         DUK_HOBJECT_SET_HSIZE(h_global, DUK_HOBJECT_GET_HSIZE(h_oldglobal));
60715 #else
60716 #error internal error in config defines
60717 #endif
60718
60719         duk_hobject_compact_props(thr, h_global);
60720         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
60721         DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL]));  /* no need to decref: ROM object */
60722         thr->builtins[DUK_BIDX_GLOBAL] = h_global;
60723         DUK_HOBJECT_INCREF(thr, h_global);
60724         DUK_D(DUK_DPRINT("duplicated global object: %!O", h_global));
60725
60726         /* Create a fresh object environment for the global scope.  This is
60727          * needed so that the global scope points to the newly created RAM-based
60728          * global object.
60729          */
60730         h_objenv = (duk_hobject *) duk_hobjenv_alloc(thr,
60731                                                      DUK_HOBJECT_FLAG_EXTENSIBLE |
60732                                                      DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
60733         DUK_ASSERT(h_objenv != NULL);
60734         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_objenv) == NULL);
60735         duk_push_hobject(thr, h_objenv);
60736
60737         DUK_ASSERT(h_global != NULL);
60738         ((duk_hobjenv *) h_objenv)->target = h_global;
60739         DUK_HOBJECT_INCREF(thr, h_global);
60740         DUK_ASSERT(((duk_hobjenv *) h_objenv)->has_this == 0);
60741
60742         DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
60743         DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV]));  /* no need to decref: ROM object */
60744         thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_objenv;
60745         DUK_HOBJECT_INCREF(thr, h_objenv);
60746         DUK_D(DUK_DPRINT("duplicated global env: %!O", h_objenv));
60747
60748         DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) h_objenv);
60749
60750         duk_pop_2(thr);  /* Pop global object and global env. */
60751 }
60752 #endif  /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
60753
60754 DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
60755         /* Setup builtins from ROM objects.  All heaps/threads will share
60756          * the same readonly objects.
60757          */
60758         duk_small_uint_t i;
60759
60760         for (i = 0; i < DUK_NUM_BUILTINS; i++) {
60761                 duk_hobject *h;
60762                 h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]);
60763                 DUK_ASSERT(h != NULL);
60764                 thr->builtins[i] = h;
60765         }
60766
60767 #if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
60768         /* By default the global object is read-only which is often much
60769          * more of an issue than having read-only built-in objects (like
60770          * RegExp, Date, etc).  Use a RAM-based copy of the global object
60771          * and the global environment object for convenience.
60772          */
60773         duk__duplicate_ram_global_object(thr);
60774 #endif
60775 }
60776 #else  /* DUK_USE_ROM_OBJECTS */
60777 DUK_LOCAL void duk__push_stridx(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
60778         duk_small_uint_t n;
60779
60780         n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
60781         DUK_ASSERT_DISABLE(n >= 0);  /* unsigned */
60782         DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
60783         duk_push_hstring_stridx(thr, n);
60784 }
60785 DUK_LOCAL void duk__push_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
60786         /* XXX: built-ins data could provide a maximum length that is
60787          * actually needed; bitpacked max length is now 256 bytes.
60788          */
60789         duk_uint8_t tmp[DUK_BD_BITPACKED_STRING_MAXLEN];
60790         duk_small_uint_t len;
60791
60792         len = duk_bd_decode_bitpacked_string(bd, tmp);
60793         duk_push_lstring(thr, (const char *) tmp, (duk_size_t) len);
60794 }
60795 DUK_LOCAL void duk__push_stridx_or_string(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
60796         duk_small_uint_t n;
60797
60798         n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
60799         if (n == 0) {
60800                 duk__push_string(thr, bd);
60801         } else {
60802                 n--;
60803                 DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
60804                 duk_push_hstring_stridx(thr, n);
60805         }
60806 }
60807 DUK_LOCAL void duk__push_double(duk_hthread *thr, duk_bitdecoder_ctx *bd) {
60808         duk_double_union du;
60809         duk_small_uint_t i;
60810
60811         for (i = 0; i < 8; i++) {
60812                 /* Encoding endianness must match target memory layout,
60813                  * build scripts and genbuiltins.py must ensure this.
60814                  */
60815                 du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
60816         }
60817
60818         duk_push_number(thr, du.d);  /* push operation normalizes NaNs */
60819 }
60820
60821 DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
60822         duk_bitdecoder_ctx bd_ctx;
60823         duk_bitdecoder_ctx *bd = &bd_ctx;  /* convenience */
60824         duk_hobject *h;
60825         duk_small_uint_t i, j;
60826
60827         DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS));
60828
60829         duk_memzero(&bd_ctx, sizeof(bd_ctx));
60830         bd->data = (const duk_uint8_t *) duk_builtins_data;
60831         bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
60832
60833         /*
60834          *  First create all built-in bare objects on the empty valstack.
60835          *
60836          *  Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value
60837          *  stack indices matching their eventual thr->builtins[] index.
60838          *
60839          *  Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS]
60840          *  will exist on the value stack during init but won't be placed
60841          *  into thr->builtins[].  These are objects referenced in some way
60842          *  from thr->builtins[] roots but which don't need to be indexed by
60843          *  Duktape through thr->builtins[] (e.g. user custom objects).
60844          *
60845          *  Internal prototypes will be incorrect (NULL) at this stage.
60846          */
60847
60848         duk_require_stack(thr, DUK_NUM_ALL_BUILTINS);
60849
60850         DUK_DD(DUK_DDPRINT("create empty built-ins"));
60851         DUK_ASSERT_TOP(thr, 0);
60852         for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
60853                 duk_small_uint_t class_num;
60854                 duk_small_int_t len = -1;  /* must be signed */
60855
60856                 class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
60857                 len = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
60858
60859                 if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
60860                         duk_small_uint_t natidx;
60861                         duk_small_int_t c_nargs;  /* must hold DUK_VARARGS */
60862                         duk_c_function c_func;
60863                         duk_int16_t magic;
60864
60865                         DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
60866                         DUK_ASSERT(len >= 0);
60867
60868                         natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
60869                         DUK_ASSERT(natidx != 0);
60870                         c_func = duk_bi_native_functions[natidx];
60871                         DUK_ASSERT(c_func != NULL);
60872
60873                         c_nargs = (duk_small_int_t) duk_bd_decode_flagged_signed(bd, DUK__NARGS_BITS, len /*def_value*/);
60874                         if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
60875                                 c_nargs = DUK_VARARGS;
60876                         }
60877
60878                         /* XXX: set magic directly here? (it could share the c_nargs arg) */
60879                         (void) duk_push_c_function_builtin(thr, c_func, c_nargs);
60880                         h = duk_known_hobject(thr, -1);
60881
60882                         /* Currently all built-in native functions are strict.
60883                          * duk_push_c_function() now sets strict flag, so
60884                          * assert for it.
60885                          */
60886                         DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));
60887
60888                         /* XXX: function properties */
60889
60890                         duk__push_stridx_or_string(thr, bd);
60891 #if defined(DUK_USE_FUNC_NAME_PROPERTY)
60892                         duk_xdef_prop_stridx_short(thr,
60893                                                    -2,
60894                                                    DUK_STRIDX_NAME,
60895                                                    DUK_PROPDESC_FLAGS_C);
60896 #else
60897                         duk_pop(thr);  /* Not very ideal but good enough for now. */
60898 #endif
60899
60900                         /* Almost all global level Function objects are constructable
60901                          * but not all: Function.prototype is a non-constructable,
60902                          * callable Function.
60903                          */
60904                         if (duk_bd_decode_flag(bd)) {
60905                                 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
60906                         } else {
60907                                 DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
60908                         }
60909
60910                         /* Cast converts magic to 16-bit signed value */
60911                         magic = (duk_int16_t) duk_bd_decode_varuint(bd);
60912                         ((duk_hnatfunc *) h)->magic = magic;
60913                 } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
60914                         duk_push_array(thr);
60915                 } else if (class_num == DUK_HOBJECT_CLASS_OBJENV) {
60916                         duk_hobjenv *env;
60917                         duk_hobject *global;
60918
60919                         DUK_ASSERT(i == DUK_BIDX_GLOBAL_ENV);
60920                         DUK_ASSERT(DUK_BIDX_GLOBAL_ENV > DUK_BIDX_GLOBAL);
60921
60922                         env = duk_hobjenv_alloc(thr,
60923                                                 DUK_HOBJECT_FLAG_EXTENSIBLE |
60924                                                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
60925                         DUK_ASSERT(env->target == NULL);
60926                         duk_push_hobject(thr, (duk_hobject *) env);
60927
60928                         global = duk_known_hobject(thr, DUK_BIDX_GLOBAL);
60929                         DUK_ASSERT(global != NULL);
60930                         env->target = global;
60931                         DUK_HOBJECT_INCREF(thr, global);
60932                         DUK_ASSERT(env->has_this == 0);
60933
60934                         DUK_ASSERT_HOBJENV_VALID(env);
60935                 } else {
60936                         DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_DECENV);
60937
60938                         (void) duk_push_object_helper(thr,
60939                                                       DUK_HOBJECT_FLAG_FASTREFS |
60940                                                       DUK_HOBJECT_FLAG_EXTENSIBLE,
60941                                                       -1);  /* no prototype or class yet */
60942
60943                 }
60944
60945                 h = duk_known_hobject(thr, -1);
60946                 DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
60947
60948                 if (i < DUK_NUM_BUILTINS) {
60949                         thr->builtins[i] = h;
60950                         DUK_HOBJECT_INCREF(thr, &h->hdr);
60951                 }
60952
60953                 if (len >= 0) {
60954                         /* In ES2015+ built-in function object .length property
60955                          * has property attributes C (configurable only):
60956                          * http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-standard-built-in-objects
60957                          *
60958                          * Array.prototype remains an Array instance in ES2015+
60959                          * and its length has attributes W (writable only).
60960                          * Because .length is now virtual for duk_harray, it is
60961                          * not encoded explicitly in init data.
60962                          */
60963
60964                         DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY);  /* .length is virtual */
60965                         duk_push_int(thr, len);
60966                         duk_xdef_prop_stridx_short(thr,
60967                                                    -2,
60968                                                    DUK_STRIDX_LENGTH,
60969                                                    DUK_PROPDESC_FLAGS_C);
60970                 }
60971
60972                 /* enable exotic behaviors last */
60973
60974                 if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
60975                         DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h));  /* set by duk_push_array() */
60976                 }
60977                 if (class_num == DUK_HOBJECT_CLASS_STRING) {
60978                         DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
60979                 }
60980
60981                 /* some assertions */
60982
60983                 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
60984                 /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
60985                 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h));
60986                 DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h));
60987                 /* DUK_HOBJECT_FLAG_NATFUNC varies */
60988                 DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(h));
60989                 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY);
60990                 /* DUK_HOBJECT_FLAG_STRICT varies */
60991                 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) ||  /* all native functions have NEWENV */
60992                            DUK_HOBJECT_HAS_NEWENV(h));
60993                 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
60994                 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
60995                 /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
60996                 /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
60997                 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));
60998
60999                 DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len));
61000         }
61001
61002         /*
61003          *  Then decode the builtins init data (see genbuiltins.py) to
61004          *  init objects.  Internal prototypes are set at this stage,
61005          *  with thr->builtins[] populated.
61006          */
61007
61008         DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
61009         for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
61010                 duk_small_uint_t t;
61011                 duk_small_uint_t num;
61012
61013                 DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
61014                 h = duk_known_hobject(thr, (duk_idx_t) i);
61015
61016                 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61017                 if (t > 0) {
61018                         t--;
61019                         DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
61020                         DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(thr, (duk_idx_t) t));
61021                 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
61022                         /* Standard native built-ins cannot inherit from
61023                          * %NativeFunctionPrototype%, they are required to
61024                          * inherit from Function.prototype directly.
61025                          */
61026                         DUK_ASSERT(thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE] != NULL);
61027                         DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
61028                 }
61029
61030                 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61031                 if (t > 0) {
61032                         /* 'prototype' property for all built-in objects (which have it) has attributes:
61033                          *  [[Writable]] = false,
61034                          *  [[Enumerable]] = false,
61035                          *  [[Configurable]] = false
61036                          */
61037                         t--;
61038                         DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
61039                         duk_dup(thr, (duk_idx_t) t);
61040                         duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_NONE);
61041                 }
61042
61043                 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61044                 if (t > 0) {
61045                         /* 'constructor' property for all built-in objects (which have it) has attributes:
61046                          *  [[Writable]] = true,
61047                          *  [[Enumerable]] = false,
61048                          *  [[Configurable]] = true
61049                          */
61050                         t--;
61051                         DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
61052                         duk_dup(thr, (duk_idx_t) t);
61053                         duk_xdef_prop_stridx(thr, (duk_idx_t) i, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC);
61054                 }
61055
61056                 /* normal valued properties */
61057                 num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61058                 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
61059                 for (j = 0; j < num; j++) {
61060                         duk_small_uint_t defprop_flags;
61061
61062                         duk__push_stridx_or_string(thr, bd);
61063
61064                         /*
61065                          *  Property attribute defaults are defined in E5 Section 15 (first
61066                          *  few pages); there is a default for all properties and a special
61067                          *  default for 'length' properties.  Variation from the defaults is
61068                          *  signaled using a single flag bit in the bitstream.
61069                          */
61070
61071                         defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
61072                                                                                  DUK__PROP_FLAGS_BITS,
61073                                                                                  (duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
61074                         defprop_flags |= DUK_DEFPROP_FORCE |
61075                                          DUK_DEFPROP_HAVE_VALUE |
61076                                          DUK_DEFPROP_HAVE_WRITABLE |
61077                                          DUK_DEFPROP_HAVE_ENUMERABLE |
61078                                          DUK_DEFPROP_HAVE_CONFIGURABLE;  /* Defaults for data properties. */
61079
61080                         /* The writable, enumerable, configurable flags in prop_flags
61081                          * match both duk_def_prop() and internal property flags.
61082                          */
61083                         DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
61084                         DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
61085                         DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);
61086
61087                         t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
61088
61089                         DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
61090                                              (long) i, (long) j, duk_get_tval(thr, -1), (unsigned long) defprop_flags, (long) t));
61091
61092                         switch (t) {
61093                         case DUK__PROP_TYPE_DOUBLE: {
61094                                 duk__push_double(thr, bd);
61095                                 break;
61096                         }
61097                         case DUK__PROP_TYPE_STRING: {
61098                                 duk__push_string(thr, bd);
61099                                 break;
61100                         }
61101                         case DUK__PROP_TYPE_STRIDX: {
61102                                 duk__push_stridx(thr, bd);
61103                                 break;
61104                         }
61105                         case DUK__PROP_TYPE_BUILTIN: {
61106                                 duk_small_uint_t bidx;
61107
61108                                 bidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61109                                 duk_dup(thr, (duk_idx_t) bidx);
61110                                 break;
61111                         }
61112                         case DUK__PROP_TYPE_UNDEFINED: {
61113                                 duk_push_undefined(thr);
61114                                 break;
61115                         }
61116                         case DUK__PROP_TYPE_BOOLEAN_TRUE: {
61117                                 duk_push_true(thr);
61118                                 break;
61119                         }
61120                         case DUK__PROP_TYPE_BOOLEAN_FALSE: {
61121                                 duk_push_false(thr);
61122                                 break;
61123                         }
61124                         case DUK__PROP_TYPE_ACCESSOR: {
61125                                 duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61126                                 duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61127                                 duk_small_uint_t accessor_magic = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61128                                 duk_c_function c_func_getter;
61129                                 duk_c_function c_func_setter;
61130
61131                                 DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
61132                                                      (long) i, duk_get_tval(thr, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) defprop_flags));
61133
61134                                 c_func_getter = duk_bi_native_functions[natidx_getter];
61135                                 if (c_func_getter != NULL) {
61136                                         duk_push_c_function_builtin_noconstruct(thr, c_func_getter, 0);  /* always 0 args */
61137                                         duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
61138                                         defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
61139                                 }
61140                                 c_func_setter = duk_bi_native_functions[natidx_setter];
61141                                 if (c_func_setter != NULL) {
61142                                         duk_push_c_function_builtin_noconstruct(thr, c_func_setter, 1);  /* always 1 arg */
61143                                         duk_set_magic(thr, -1, (duk_int_t) accessor_magic);
61144                                         defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
61145                                 }
61146
61147                                 /* Writable flag doesn't make sense for an accessor. */
61148                                 DUK_ASSERT((defprop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0);  /* genbuiltins.py ensures */
61149
61150                                 defprop_flags &= ~(DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
61151                                 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE;
61152                                 break;
61153                         }
61154                         default: {
61155                                 /* exhaustive */
61156                                 DUK_UNREACHABLE();
61157                         }
61158                         }
61159
61160                         duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
61161                         DUK_ASSERT_TOP(thr, DUK_NUM_ALL_BUILTINS);
61162                 }
61163
61164                 /* native function properties */
61165                 num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61166                 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
61167                 for (j = 0; j < num; j++) {
61168                         duk_hstring *h_key;
61169                         duk_small_uint_t natidx;
61170                         duk_int_t c_nargs;  /* must hold DUK_VARARGS */
61171                         duk_small_uint_t c_length;
61172                         duk_int16_t magic;
61173                         duk_c_function c_func;
61174                         duk_hnatfunc *h_func;
61175 #if defined(DUK_USE_LIGHTFUNC_BUILTINS)
61176                         duk_small_int_t lightfunc_eligible;
61177 #endif
61178                         duk_small_uint_t defprop_flags;
61179
61180                         duk__push_stridx_or_string(thr, bd);
61181                         h_key = duk_known_hstring(thr, -1);
61182                         DUK_UNREF(h_key);
61183                         natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
61184
61185                         c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
61186                         c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_uint32_t) c_length /*def_value*/);
61187                         if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
61188                                 c_nargs = DUK_VARARGS;
61189                         }
61190
61191                         c_func = duk_bi_native_functions[natidx];
61192
61193                         DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld",
61194                                              (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length,
61195                                              (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));
61196
61197                         /* Cast converts magic to 16-bit signed value */
61198                         magic = (duk_int16_t) duk_bd_decode_varuint(bd);
61199
61200 #if defined(DUK_USE_LIGHTFUNC_BUILTINS)
61201                         lightfunc_eligible =
61202                                 ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) &&
61203                                 (c_length <= DUK_LFUNC_LENGTH_MAX) &&
61204                                 (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
61205
61206                         /* These functions have trouble working as lightfuncs.
61207                          * Some of them have specific asserts and some may have
61208                          * additional properties (e.g. 'require.id' may be written).
61209                          */
61210                         if (c_func == duk_bi_global_object_eval) {
61211                                 lightfunc_eligible = 0;
61212                         }
61213 #if defined(DUK_USE_COROUTINE_SUPPORT)
61214                         if (c_func == duk_bi_thread_yield ||
61215                             c_func == duk_bi_thread_resume) {
61216                                 lightfunc_eligible = 0;
61217                         }
61218 #endif
61219                         if (c_func == duk_bi_function_prototype_call ||
61220                             c_func == duk_bi_function_prototype_apply ||
61221                             c_func == duk_bi_reflect_apply ||
61222                             c_func == duk_bi_reflect_construct) {
61223                                 lightfunc_eligible = 0;
61224                         }
61225
61226                         if (lightfunc_eligible) {
61227                                 duk_tval tv_lfunc;
61228                                 duk_small_uint_t lf_nargs = (duk_small_uint_t) (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
61229                                 duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
61230                                 DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
61231                                 duk_push_tval(thr, &tv_lfunc);
61232                                 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)));
61233                                 goto lightfunc_skip;
61234                         }
61235
61236                         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));
61237 #endif  /* DUK_USE_LIGHTFUNC_BUILTINS */
61238
61239                         /* [ (builtin objects) name ] */
61240
61241                         duk_push_c_function_builtin_noconstruct(thr, c_func, c_nargs);
61242                         h_func = duk_known_hnatfunc(thr, -1);
61243                         DUK_UNREF(h_func);
61244
61245                         /* XXX: add into init data? */
61246
61247                         /* Special call handling, not described in init data. */
61248                         if (c_func == duk_bi_global_object_eval ||
61249                             c_func == duk_bi_function_prototype_call ||
61250                             c_func == duk_bi_function_prototype_apply ||
61251                             c_func == duk_bi_reflect_apply ||
61252                             c_func == duk_bi_reflect_construct) {
61253                                 DUK_HOBJECT_SET_SPECIAL_CALL((duk_hobject *) h_func);
61254                         }
61255
61256                         /* Currently all built-in native functions are strict.
61257                          * This doesn't matter for many functions, but e.g.
61258                          * String.prototype.charAt (and other string functions)
61259                          * rely on being strict so that their 'this' binding is
61260                          * not automatically coerced.
61261                          */
61262                         DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);
61263
61264                         /* No built-in functions are constructable except the top
61265                          * level ones (Number, etc).
61266                          */
61267                         DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));
61268
61269                         /* XXX: any way to avoid decoding magic bit; there are quite
61270                          * many function properties and relatively few with magic values.
61271                          */
61272                         h_func->magic = magic;
61273
61274                         /* [ (builtin objects) name func ] */
61275
61276                         duk_push_uint(thr, c_length);
61277                         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
61278
61279                         duk_dup_m2(thr);
61280                         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
61281
61282                         /* XXX: other properties of function instances; 'arguments', 'caller'. */
61283
61284                         DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
61285                                            (long) i, (long) j, (duk_tval *) duk_get_tval(thr, -1)));
61286
61287                         /* [ (builtin objects) name func ] */
61288
61289                         /*
61290                          *  The default property attributes are correct for all
61291                          *  function valued properties of built-in objects now.
61292                          */
61293
61294 #if defined(DUK_USE_LIGHTFUNC_BUILTINS)
61295                  lightfunc_skip:
61296 #endif
61297
61298                         defprop_flags = (duk_small_uint_t) duk_bd_decode_flagged(bd,
61299                                                                                  DUK__PROP_FLAGS_BITS,
61300                                                                                  (duk_uint32_t) DUK_PROPDESC_FLAGS_WC);
61301                         defprop_flags |= DUK_DEFPROP_FORCE |
61302                                          DUK_DEFPROP_HAVE_VALUE |
61303                                          DUK_DEFPROP_HAVE_WRITABLE |
61304                                          DUK_DEFPROP_HAVE_ENUMERABLE |
61305                                          DUK_DEFPROP_HAVE_CONFIGURABLE;
61306                         DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
61307                         DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
61308                         DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);
61309
61310                         duk_def_prop(thr, (duk_idx_t) i, defprop_flags);
61311
61312                         /* [ (builtin objects) ] */
61313                 }
61314         }
61315
61316         /*
61317          *  Special post-tweaks, for cases not covered by the init data format.
61318          *
61319          *  - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
61320          *    toGMTString is required to have the same Function object as
61321          *    toUTCString in E5 Section B.2.6.  Note that while Smjs respects
61322          *    this, V8 does not (the Function objects are distinct).
61323          *
61324          *  - Make DoubleError non-extensible.
61325          *
61326          *  - Add info about most important effective compile options to Duktape.
61327          *
61328          *  - Possibly remove some properties (values or methods) which are not
61329          *    desirable with current feature options but are not currently
61330          *    conditional in init data.
61331          */
61332
61333 #if defined(DUK_USE_DATE_BUILTIN)
61334         duk_get_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
61335         duk_xdef_prop_stridx_short(thr, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
61336 #endif
61337
61338         h = duk_known_hobject(thr, DUK_BIDX_DOUBLE_ERROR);
61339         DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
61340
61341 #if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
61342         DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
61343         (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW);
61344 #endif
61345
61346 #if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
61347         DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
61348         (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW);
61349 #endif
61350
61351         /* XXX: relocate */
61352         duk_push_string(thr,
61353                         /* Endianness indicator */
61354 #if defined(DUK_USE_INTEGER_LE)
61355                         "l"
61356 #elif defined(DUK_USE_INTEGER_BE)
61357                         "b"
61358 #elif defined(DUK_USE_INTEGER_ME)  /* integer mixed endian not really used now */
61359                         "m"
61360 #else
61361                         "?"
61362 #endif
61363 #if defined(DUK_USE_DOUBLE_LE)
61364                         "l"
61365 #elif defined(DUK_USE_DOUBLE_BE)
61366                         "b"
61367 #elif defined(DUK_USE_DOUBLE_ME)
61368                         "m"
61369 #else
61370                         "?"
61371 #endif
61372                         " "
61373                         /* Packed or unpacked tval */
61374 #if defined(DUK_USE_PACKED_TVAL)
61375                         "p"
61376 #else
61377                         "u"
61378 #endif
61379 #if defined(DUK_USE_FASTINT)
61380                         "f"
61381 #endif
61382                         " "
61383                         /* Low memory/performance options */
61384 #if defined(DUK_USE_STRTAB_PTRCOMP)
61385                         "s"
61386 #endif
61387 #if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
61388                         "n"
61389 #endif
61390 #if defined(DUK_USE_HEAPPTR16)
61391                         "h"
61392 #endif
61393 #if defined(DUK_USE_DATAPTR16)
61394                         "d"
61395 #endif
61396 #if defined(DUK_USE_FUNCPTR16)
61397                         "f"
61398 #endif
61399 #if defined(DUK_USE_REFCOUNT16)
61400                         "R"
61401 #endif
61402 #if defined(DUK_USE_STRHASH16)
61403                         "H"
61404 #endif
61405 #if defined(DUK_USE_STRLEN16)
61406                         "S"
61407 #endif
61408 #if defined(DUK_USE_BUFLEN16)
61409                         "B"
61410 #endif
61411 #if defined(DUK_USE_OBJSIZES16)
61412                         "O"
61413 #endif
61414 #if defined(DUK_USE_LIGHTFUNC_BUILTINS)
61415                         "L"
61416 #endif
61417 #if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS)
61418                         /* XXX: This won't be shown in practice now
61419                          * because this code is not run when builtins
61420                          * are in ROM.
61421                          */
61422                         "Z"
61423 #endif
61424 #if defined(DUK_USE_LITCACHE_SIZE)
61425                         "l"
61426 #endif
61427                         " "
61428                         /* Object property allocation layout */
61429 #if defined(DUK_USE_HOBJECT_LAYOUT_1)
61430                         "p1"
61431 #elif defined(DUK_USE_HOBJECT_LAYOUT_2)
61432                         "p2"
61433 #elif defined(DUK_USE_HOBJECT_LAYOUT_3)
61434                         "p3"
61435 #else
61436                         "p?"
61437 #endif
61438                         " "
61439                         /* Alignment guarantee */
61440 #if (DUK_USE_ALIGN_BY == 4)
61441                         "a4"
61442 #elif (DUK_USE_ALIGN_BY == 8)
61443                         "a8"
61444 #elif (DUK_USE_ALIGN_BY == 1)
61445                         "a1"
61446 #else
61447 #error invalid DUK_USE_ALIGN_BY
61448 #endif
61449                         " "
61450                         /* Architecture, OS, and compiler strings */
61451                         DUK_USE_ARCH_STRING
61452                         " "
61453                         DUK_USE_OS_STRING
61454                         " "
61455                         DUK_USE_COMPILER_STRING);
61456         duk_xdef_prop_stridx_short(thr, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
61457
61458         /*
61459          *  Since built-ins are not often extended, compact them.
61460          */
61461
61462         DUK_DD(DUK_DDPRINT("compact built-ins"));
61463         for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
61464                 duk_hobject_compact_props(thr, duk_known_hobject(thr, (duk_idx_t) i));
61465         }
61466
61467         DUK_D(DUK_DPRINT("INITBUILTINS END"));
61468
61469 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
61470         for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
61471                 DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
61472                                    (long) i, (duk_heaphdr *) duk_require_hobject(thr, i)));
61473         }
61474 #endif
61475
61476         /*
61477          *  Pop built-ins from stack: they are now INCREF'd and
61478          *  reachable from the builtins[] array or indirectly
61479          *  through builtins[].
61480          */
61481
61482         duk_set_top(thr, 0);
61483         DUK_ASSERT_TOP(thr, 0);
61484 }
61485 #endif  /* DUK_USE_ROM_OBJECTS */
61486
61487 DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
61488         duk_small_uint_t i;
61489
61490         for (i = 0; i < DUK_NUM_BUILTINS; i++) {
61491                 thr_to->builtins[i] = thr_from->builtins[i];
61492                 DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]);  /* side effect free */
61493         }
61494 }
61495
61496 /* automatic undefs */
61497 #undef DUK__LENGTH_PROP_BITS
61498 #undef DUK__NARGS_BITS
61499 #undef DUK__NARGS_VARARGS_MARKER
61500 #undef DUK__PROP_FLAGS_BITS
61501 #undef DUK__PROP_TYPE_ACCESSOR
61502 #undef DUK__PROP_TYPE_BITS
61503 #undef DUK__PROP_TYPE_BOOLEAN_FALSE
61504 #undef DUK__PROP_TYPE_BOOLEAN_TRUE
61505 #undef DUK__PROP_TYPE_BUILTIN
61506 #undef DUK__PROP_TYPE_DOUBLE
61507 #undef DUK__PROP_TYPE_STRIDX
61508 #undef DUK__PROP_TYPE_STRING
61509 #undef DUK__PROP_TYPE_UNDEFINED
61510 #line 1 "duk_hthread_misc.c"
61511 /*
61512  *  Thread support.
61513  */
61514
61515 /* #include duk_internal.h -> already included */
61516
61517 DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) {
61518         DUK_ASSERT(thr != NULL);
61519
61520         while (thr->callstack_curr != NULL) {
61521                 duk_hthread_activation_unwind_norz(thr);
61522         }
61523
61524         thr->valstack_bottom = thr->valstack;
61525         duk_set_top(thr, 0);  /* unwinds valstack, updating refcounts */
61526
61527         thr->state = DUK_HTHREAD_STATE_TERMINATED;
61528
61529         /* Here we could remove references to built-ins, but it may not be
61530          * worth the effort because built-ins are quite likely to be shared
61531          * with another (unterminated) thread, and terminated threads are also
61532          * usually garbage collected quite quickly.
61533          *
61534          * We could also shrink the value stack here, but that also may not
61535          * be worth the effort for the same reason.
61536          */
61537
61538         DUK_REFZERO_CHECK_SLOW(thr);
61539 }
61540
61541 #if defined(DUK_USE_DEBUGGER_SUPPORT)
61542 DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) {
61543         duk_instr_t *bcode;
61544
61545         DUK_ASSERT(thr != NULL);
61546         DUK_ASSERT(act != NULL);
61547         DUK_UNREF(thr);
61548
61549         /* XXX: store 'bcode' pointer to activation for faster lookup? */
61550         if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) {
61551                 bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func));
61552                 return (duk_uint_fast32_t) (act->curr_pc - bcode);
61553         }
61554         return 0;
61555 }
61556 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
61557
61558 DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) {
61559         duk_instr_t *bcode;
61560         duk_uint_fast32_t ret;
61561
61562         DUK_ASSERT(thr != NULL);
61563         DUK_ASSERT(act != NULL);
61564         DUK_UNREF(thr);
61565
61566         if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) {
61567                 bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func));
61568                 ret = (duk_uint_fast32_t) (act->curr_pc - bcode);
61569                 if (ret > 0) {
61570                         ret--;
61571                 }
61572                 return ret;
61573         }
61574         return 0;
61575 }
61576
61577 /* Write bytecode executor's curr_pc back to topmost activation (if any). */
61578 DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) {
61579         duk_activation *act;
61580
61581         DUK_ASSERT(thr != NULL);
61582
61583         if (thr->ptr_curr_pc != NULL) {
61584                 /* ptr_curr_pc != NULL only when bytecode executor is active. */
61585                 DUK_ASSERT(thr->callstack_top > 0);
61586                 DUK_ASSERT(thr->callstack_curr != NULL);
61587                 act = thr->callstack_curr;
61588                 DUK_ASSERT(act != NULL);
61589                 act->curr_pc = *thr->ptr_curr_pc;
61590         }
61591 }
61592
61593 DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) {
61594         duk_activation *act;
61595
61596         DUK_ASSERT(thr != NULL);
61597
61598         if (thr->ptr_curr_pc != NULL) {
61599                 /* ptr_curr_pc != NULL only when bytecode executor is active. */
61600                 DUK_ASSERT(thr->callstack_top > 0);
61601                 DUK_ASSERT(thr->callstack_curr != NULL);
61602                 act = thr->callstack_curr;
61603                 DUK_ASSERT(act != NULL);
61604                 act->curr_pc = *thr->ptr_curr_pc;
61605                 thr->ptr_curr_pc = NULL;
61606         }
61607 }
61608 #line 1 "duk_hthread_stacks.c"
61609 /*
61610  *  Thread stack (mainly call stack) primitives: allocation of activations,
61611  *  unwinding catchers and activations, etc.
61612  *
61613  *  Value stack handling is a part of the API implementation.
61614  */
61615
61616 /* #include duk_internal.h -> already included */
61617
61618 /* Unwind the topmost catcher of the current activation (caller must check that
61619  * both exist) without side effects.
61620  */
61621 DUK_INTERNAL void duk_hthread_catcher_unwind_norz(duk_hthread *thr, duk_activation *act) {
61622         duk_catcher *cat;
61623
61624         DUK_ASSERT(thr != NULL);
61625         DUK_ASSERT(act != NULL);
61626         DUK_ASSERT(act->cat != NULL);  /* caller must check */
61627         cat = act->cat;
61628         DUK_ASSERT(cat != NULL);
61629
61630         DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is done)", (void *) cat));
61631
61632         if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
61633                 duk_hobject *env;
61634
61635                 env = act->lex_env;             /* current lex_env of the activation (created for catcher) */
61636                 DUK_ASSERT(env != NULL);        /* must be, since env was created when catcher was created */
61637                 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);  /* prototype is lex_env before catcher created */
61638                 DUK_HOBJECT_INCREF(thr, act->lex_env);
61639                 DUK_HOBJECT_DECREF_NORZ(thr, env);
61640
61641                 /* There is no need to decref anything else than 'env': if 'env'
61642                  * becomes unreachable, refzero will handle decref'ing its prototype.
61643                  */
61644         }
61645
61646         act->cat = cat->parent;
61647         duk_hthread_catcher_free(thr, cat);
61648 }
61649
61650 /* Same as above, but caller is certain no catcher-related lexenv may exist. */
61651 DUK_INTERNAL void duk_hthread_catcher_unwind_nolexenv_norz(duk_hthread *thr, duk_activation *act) {
61652         duk_catcher *cat;
61653
61654         DUK_ASSERT(thr != NULL);
61655         DUK_ASSERT(act != NULL);
61656         DUK_ASSERT(act->cat != NULL);  /* caller must check */
61657         cat = act->cat;
61658         DUK_ASSERT(cat != NULL);
61659
61660         DUK_DDD(DUK_DDDPRINT("unwinding catch stack entry %p (lexenv check is not done)", (void *) cat));
61661
61662         DUK_ASSERT(!DUK_CAT_HAS_LEXENV_ACTIVE(cat));
61663
61664         act->cat = cat->parent;
61665         duk_hthread_catcher_free(thr, cat);
61666 }
61667
61668 DUK_LOCAL
61669 #if defined(DUK_USE_CACHE_CATCHER)
61670 DUK_NOINLINE
61671 #endif
61672 duk_catcher *duk__hthread_catcher_alloc_slow(duk_hthread *thr) {
61673         duk_catcher *cat;
61674
61675         cat = (duk_catcher *) DUK_ALLOC_CHECKED(thr, sizeof(duk_catcher));
61676         DUK_ASSERT(cat != NULL);
61677         return cat;
61678 }
61679
61680 #if defined(DUK_USE_CACHE_CATCHER)
61681 DUK_INTERNAL DUK_INLINE duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) {
61682         duk_catcher *cat;
61683
61684         DUK_ASSERT(thr != NULL);
61685
61686         cat = thr->heap->catcher_free;
61687         if (DUK_LIKELY(cat != NULL)) {
61688                 thr->heap->catcher_free = cat->parent;
61689                 return cat;
61690         }
61691
61692         return duk__hthread_catcher_alloc_slow(thr);
61693 }
61694 #else  /* DUK_USE_CACHE_CATCHER */
61695 DUK_INTERNAL duk_catcher *duk_hthread_catcher_alloc(duk_hthread *thr) {
61696         return duk__hthread_catcher_alloc_slow(thr);
61697 }
61698 #endif  /* DUK_USE_CACHE_CATCHER */
61699
61700 DUK_INTERNAL void duk_hthread_catcher_free(duk_hthread *thr, duk_catcher *cat) {
61701         DUK_ASSERT(thr != NULL);
61702         DUK_ASSERT(cat != NULL);
61703
61704 #if defined(DUK_USE_CACHE_CATCHER)
61705         /* Unconditional caching for now; freed in mark-and-sweep. */
61706         cat->parent = thr->heap->catcher_free;
61707         thr->heap->catcher_free = cat;
61708 #else
61709         DUK_FREE_CHECKED(thr, (void *) cat);
61710 #endif
61711 }
61712
61713 DUK_LOCAL
61714 #if defined(DUK_USE_CACHE_ACTIVATION)
61715 DUK_NOINLINE
61716 #endif
61717 duk_activation *duk__hthread_activation_alloc_slow(duk_hthread *thr) {
61718         duk_activation *act;
61719
61720         act = (duk_activation *) DUK_ALLOC_CHECKED(thr, sizeof(duk_activation));
61721         DUK_ASSERT(act != NULL);
61722         return act;
61723 }
61724
61725 #if defined(DUK_USE_CACHE_ACTIVATION)
61726 DUK_INTERNAL DUK_INLINE duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) {
61727         duk_activation *act;
61728
61729         DUK_ASSERT(thr != NULL);
61730
61731         act = thr->heap->activation_free;
61732         if (DUK_LIKELY(act != NULL)) {
61733                 thr->heap->activation_free = act->parent;
61734                 return act;
61735         }
61736
61737         return duk__hthread_activation_alloc_slow(thr);
61738 }
61739 #else  /* DUK_USE_CACHE_ACTIVATION */
61740 DUK_INTERNAL duk_activation *duk_hthread_activation_alloc(duk_hthread *thr) {
61741         return duk__hthread_activation_alloc_slow(thr);
61742 }
61743 #endif  /* DUK_USE_CACHE_ACTIVATION */
61744
61745
61746 DUK_INTERNAL void duk_hthread_activation_free(duk_hthread *thr, duk_activation *act) {
61747         DUK_ASSERT(thr != NULL);
61748         DUK_ASSERT(act != NULL);
61749
61750 #if defined(DUK_USE_CACHE_ACTIVATION)
61751         /* Unconditional caching for now; freed in mark-and-sweep. */
61752         act->parent = thr->heap->activation_free;
61753         thr->heap->activation_free = act;
61754 #else
61755         DUK_FREE_CHECKED(thr, (void *) act);
61756 #endif
61757 }
61758
61759 /* Internal helper: process the unwind for the topmost activation of a thread,
61760  * but leave the duk_activation in place for possible tailcall reuse.
61761  */
61762 DUK_LOCAL void duk__activation_unwind_nofree_norz(duk_hthread *thr) {
61763 #if defined(DUK_USE_DEBUGGER_SUPPORT)
61764         duk_heap *heap;
61765 #endif
61766         duk_activation *act;
61767         duk_hobject *func;
61768         duk_hobject *tmp;
61769
61770         DUK_ASSERT(thr != NULL);
61771         DUK_ASSERT(thr->callstack_curr != NULL);  /* caller must check */
61772         DUK_ASSERT(thr->callstack_top > 0);
61773         act = thr->callstack_curr;
61774         DUK_ASSERT(act != NULL);
61775         /* With lightfuncs, act 'func' may be NULL. */
61776
61777         /* With duk_activation records allocated separately, 'act' is a stable
61778          * pointer and not affected by side effects.
61779          */
61780
61781 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
61782         /*
61783          *  Restore 'caller' property for non-strict callee functions.
61784          */
61785
61786         func = DUK_ACT_GET_FUNC(act);
61787         if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
61788                 duk_tval *tv_caller;
61789                 duk_tval tv_tmp;
61790                 duk_hobject *h_tmp;
61791
61792                 tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
61793
61794                 /* The act->prev_caller should only be set if the entry for 'caller'
61795                  * exists (as it is only set in that case, and the property is not
61796                  * configurable), but handle all the cases anyway.
61797                  */
61798
61799                 if (tv_caller) {
61800                         DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
61801                         if (act->prev_caller) {
61802                                 /* Just transfer the refcount from act->prev_caller to tv_caller,
61803                                  * so no need for a refcount update.  This is the expected case.
61804                                  */
61805                                 DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
61806                                 act->prev_caller = NULL;
61807                         } else {
61808                                 DUK_TVAL_SET_NULL(tv_caller);   /* no incref needed */
61809                                 DUK_ASSERT(act->prev_caller == NULL);
61810                         }
61811                         DUK_TVAL_DECREF_NORZ(thr, &tv_tmp);
61812                 } else {
61813                         h_tmp = act->prev_caller;
61814                         if (h_tmp) {
61815                                 act->prev_caller = NULL;
61816                                 DUK_HOBJECT_DECREF_NORZ(thr, h_tmp);
61817                         }
61818                 }
61819                 DUK_ASSERT(act->prev_caller == NULL);
61820         }
61821 #endif
61822
61823         /*
61824          *  Unwind debugger state.  If we unwind while stepping
61825          *  (for any step type), pause execution.  This is the
61826          *  only place explicitly handling a step out.
61827          */
61828
61829 #if defined(DUK_USE_DEBUGGER_SUPPORT)
61830         heap = thr->heap;
61831         if (heap->dbg_pause_act == thr->callstack_curr) {
61832                 if (heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_EXIT) {
61833                         DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function exit"));
61834                         duk_debug_set_paused(heap);
61835                 } else {
61836                         DUK_D(DUK_DPRINT("unwound past dbg_pause_act, set to NULL"));
61837                         heap->dbg_pause_act = NULL;  /* avoid stale pointers */
61838                 }
61839                 DUK_ASSERT(heap->dbg_pause_act == NULL);
61840         }
61841 #endif
61842
61843         /*
61844          *  Unwind catchers.
61845          *
61846          *  Since there are no references in the catcher structure,
61847          *  unwinding is quite simple.  The only thing we need to
61848          *  look out for is popping a possible lexical environment
61849          *  established for an active catch clause.
61850          */
61851
61852         while (act->cat != NULL) {
61853                 duk_hthread_catcher_unwind_norz(thr, act);
61854         }
61855
61856         /*
61857          *  Close environment record(s) if they exist.
61858          *
61859          *  Only variable environments are closed.  If lex_env != var_env, it
61860          *  cannot currently contain any register bound declarations.
61861          *
61862          *  Only environments created for a NEWENV function are closed.  If an
61863          *  environment is created for e.g. an eval call, it must not be closed.
61864          */
61865
61866         func = DUK_ACT_GET_FUNC(act);
61867         if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
61868                 DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
61869                 goto skip_env_close;
61870         }
61871         /* func is NULL for lightfunc */
61872
61873         /* Catch sites are required to clean up their environments
61874          * in FINALLY part before propagating, so this should
61875          * always hold here.
61876          */
61877         DUK_ASSERT(act->lex_env == act->var_env);
61878
61879         /* XXX: Closing the environment record copies values from registers
61880          * into the scope object.  It's side effect free as such, but may
61881          * currently run out of memory which causes an error throw.  This is
61882          * an actual sandboxing problem for error unwinds, and needs to be
61883          * fixed e.g. by preallocating the scope property slots.
61884          */
61885         if (act->var_env != NULL) {
61886                 DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
61887                                      (void *) act->var_env, (duk_heaphdr *) act->var_env));
61888                 duk_js_close_environment_record(thr, act->var_env);
61889         }
61890
61891  skip_env_close:
61892
61893         /*
61894          *  Update preventcount
61895          */
61896
61897         if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
61898                 DUK_ASSERT(thr->callstack_preventcount >= 1);
61899                 thr->callstack_preventcount--;
61900         }
61901
61902         /*
61903          *  Reference count updates, using NORZ macros so we don't
61904          *  need to handle side effects.
61905          *
61906          *  duk_activation pointers like act->var_env are intentionally
61907          *  left as garbage and not NULLed.  Without side effects they
61908          *  can't be used when the values are dangling/garbage.
61909          */
61910
61911         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->var_env);
61912         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, act->lex_env);
61913         tmp = DUK_ACT_GET_FUNC(act);
61914         DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
61915         DUK_UNREF(tmp);
61916 }
61917
61918 /* Unwind topmost duk_activation of a thread, caller must ensure that an
61919  * activation exists.  The call is side effect free, except that scope
61920  * closure may currently throw an out-of-memory error.
61921  */
61922 DUK_INTERNAL void duk_hthread_activation_unwind_norz(duk_hthread *thr) {
61923         duk_activation *act;
61924
61925         duk__activation_unwind_nofree_norz(thr);
61926
61927         DUK_ASSERT(thr->callstack_curr != NULL);
61928         DUK_ASSERT(thr->callstack_top > 0);
61929         act = thr->callstack_curr;
61930         thr->callstack_curr = act->parent;
61931         thr->callstack_top--;
61932
61933         /* Ideally we'd restore value stack reserve here to caller's value.
61934          * This doesn't work for current unwind call sites however, because
61935          * the current (unwound) value stack top may be above the reserve.
61936          * Thus value stack reserve is restored by the call sites.
61937          */
61938
61939         /* XXX: inline for performance builds? */
61940         duk_hthread_activation_free(thr, act);
61941
61942         /* We could clear the book-keeping variables like retval_byteoff for
61943          * the topmost activation, but don't do so now as it's not necessary.
61944          */
61945 }
61946
61947 DUK_INTERNAL void duk_hthread_activation_unwind_reuse_norz(duk_hthread *thr) {
61948         duk__activation_unwind_nofree_norz(thr);
61949 }
61950
61951 /* Get duk_activation for given callstack level or NULL if level is invalid
61952  * or deeper than the call stack.  Level -1 refers to current activation, -2
61953  * to its caller, etc.  Starting from Duktape 2.2 finding the activation is
61954  * a linked list scan which gets more expensive the deeper the lookup is.
61955  */
61956 DUK_INTERNAL duk_activation *duk_hthread_get_activation_for_level(duk_hthread *thr, duk_int_t level) {
61957         duk_activation *act;
61958
61959         if (level >= 0) {
61960                 return NULL;
61961         }
61962         act = thr->callstack_curr;
61963         for (;;) {
61964                 if (act == NULL) {
61965                         return act;
61966                 }
61967                 if (level == -1) {
61968                         return act;
61969                 }
61970                 level++;
61971                 act = act->parent;
61972         }
61973         /* never here */
61974 }
61975
61976 #if defined(DUK_USE_FINALIZER_TORTURE)
61977 DUK_INTERNAL void duk_hthread_valstack_torture_realloc(duk_hthread *thr) {
61978         duk_size_t alloc_size;
61979         duk_tval *new_ptr;
61980         duk_ptrdiff_t alloc_end_off;
61981         duk_ptrdiff_t end_off;
61982         duk_ptrdiff_t bottom_off;
61983         duk_ptrdiff_t top_off;
61984
61985         if (thr->valstack == NULL) {
61986                 DUK_D(DUK_DPRINT("skip valstack torture realloc, valstack is NULL"));
61987                 return;
61988         }
61989
61990         alloc_end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_alloc_end - (duk_uint8_t *) thr->valstack);
61991         end_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
61992         bottom_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
61993         top_off = (duk_ptrdiff_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack);
61994         alloc_size = (duk_size_t) alloc_end_off;
61995         if (alloc_size == 0) {
61996                 DUK_D(DUK_DPRINT("skip valstack torture realloc, alloc_size is zero"));
61997                 return;
61998         }
61999
62000         /* Use DUK_ALLOC_RAW() to avoid side effects. */
62001         new_ptr = (duk_tval *) DUK_ALLOC_RAW(thr->heap, alloc_size);
62002         if (new_ptr != NULL) {
62003                 duk_memcpy((void *) new_ptr, (const void *) thr->valstack, alloc_size);
62004                 duk_memset((void *) thr->valstack, 0x55, alloc_size);
62005                 DUK_FREE_CHECKED(thr, (void *) thr->valstack);
62006                 thr->valstack = new_ptr;
62007                 thr->valstack_alloc_end = (duk_tval *) ((duk_uint8_t *) new_ptr + alloc_end_off);
62008                 thr->valstack_end = (duk_tval *) ((duk_uint8_t *) new_ptr + end_off);
62009                 thr->valstack_bottom = (duk_tval *) ((duk_uint8_t *) new_ptr + bottom_off);
62010                 thr->valstack_top = (duk_tval *) ((duk_uint8_t *) new_ptr + top_off);
62011         } else {
62012                 DUK_D(DUK_DPRINT("failed to realloc valstack for torture, ignore"));
62013         }
62014 }
62015 #endif  /* DUK_USE_FINALIZER_TORTURE */
62016 #line 1 "duk_js_arith.c"
62017 /*
62018  *  Shared helpers for arithmetic operations
62019  */
62020
62021 /* #include duk_internal.h -> already included */
62022
62023 /* ECMAScript modulus ('%') does not match IEEE 754 "remainder" operation
62024  * (implemented by remainder() in C99) but does seem to match ANSI C fmod().
62025  * Compare E5 Section 11.5.3 and "man fmod".
62026  */
62027 DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) {
62028 #if defined(DUK_USE_POW_WORKAROUNDS)
62029         /* Specific fixes to common fmod() implementation issues:
62030          * - test-bug-mingw-math-issues.js
62031          */
62032         if (DUK_ISINF(d2)) {
62033                 if (DUK_ISINF(d1)) {
62034                         return DUK_DOUBLE_NAN;
62035                 } else {
62036                         return d1;
62037                 }
62038         } else if (d1 == 0.0) {
62039                 /* d1 +/-0 is returned as is (preserving sign) except when
62040                  * d2 is zero or NaN.
62041                  */
62042                 if (d2 == 0.0 || DUK_ISNAN(d2)) {
62043                         return DUK_DOUBLE_NAN;
62044                 } else {
62045                         return d1;
62046                 }
62047         }
62048 #else
62049         /* Some ISO C assumptions. */
62050         DUK_ASSERT(DUK_FMOD(1.0, DUK_DOUBLE_INFINITY) == 1.0);
62051         DUK_ASSERT(DUK_FMOD(-1.0, DUK_DOUBLE_INFINITY) == -1.0);
62052         DUK_ASSERT(DUK_FMOD(1.0, -DUK_DOUBLE_INFINITY) == 1.0);
62053         DUK_ASSERT(DUK_FMOD(-1.0, -DUK_DOUBLE_INFINITY) == -1.0);
62054         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
62055         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
62056         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
62057         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
62058         DUK_ASSERT(DUK_FMOD(0.0, 1.0) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, 1.0)) == 0);
62059         DUK_ASSERT(DUK_FMOD(-0.0, 1.0) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, 1.0)) != 0);
62060         DUK_ASSERT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
62061         DUK_ASSERT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY)) != 0);
62062         DUK_ASSERT(DUK_FMOD(0.0, -DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
62063         DUK_ASSERT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY)) != 0);
62064         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, 0.0)));
62065         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, 0.0)));
62066         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, -0.0)));
62067         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, -0.0)));
62068         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, DUK_DOUBLE_NAN)));
62069         DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, DUK_DOUBLE_NAN)));
62070 #endif
62071
62072         return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
62073 }
62074
62075 /* Shared helper for Math.pow() and exponentiation operator. */
62076 DUK_INTERNAL double duk_js_arith_pow(double x, double y) {
62077         /* The ANSI C pow() semantics differ from ECMAScript.
62078          *
62079          * E.g. when x==1 and y is +/- infinite, the ECMAScript required
62080          * result is NaN, while at least Linux pow() returns 1.
62081          */
62082
62083         duk_small_int_t cx, cy, sx;
62084
62085         DUK_UNREF(cx);
62086         DUK_UNREF(sx);
62087         cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
62088
62089         if (cy == DUK_FP_NAN) {
62090                 goto ret_nan;
62091         }
62092         if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) {
62093                 goto ret_nan;
62094         }
62095
62096 #if defined(DUK_USE_POW_WORKAROUNDS)
62097         /* Specific fixes to common pow() implementation issues:
62098          *   - test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least)
62099          *   - test-bug-mingw-math-issues.js
62100          */
62101         cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
62102         if (cx == DUK_FP_ZERO && y < 0.0) {
62103                 sx = (duk_small_int_t) DUK_SIGNBIT(x);
62104                 if (sx == 0) {
62105                         /* Math.pow(+0,y) should be Infinity when y<0.  NetBSD pow()
62106                          * returns -Infinity instead when y is <0 and finite.  The
62107                          * if-clause also catches y == -Infinity (which works even
62108                          * without the fix).
62109                          */
62110                         return DUK_DOUBLE_INFINITY;
62111                 } else {
62112                         /* Math.pow(-0,y) where y<0 should be:
62113                          *   - -Infinity if y<0 and an odd integer
62114                          *   - Infinity if y<0 but not an odd integer
62115                          * NetBSD pow() returns -Infinity for all finite y<0.  The
62116                          * if-clause also catches y == -Infinity (which works even
62117                          * without the fix).
62118                          */
62119
62120                         /* fmod() return value has same sign as input (negative) so
62121                          * the result here will be in the range ]-2,0], -1 indicates
62122                          * odd.  If x is -Infinity, NaN is returned and the odd check
62123                          * always concludes "not odd" which results in desired outcome.
62124                          */
62125                         double tmp = DUK_FMOD(y, 2);
62126                         if (tmp == -1.0) {
62127                                 return -DUK_DOUBLE_INFINITY;
62128                         } else {
62129                                 /* Not odd, or y == -Infinity */
62130                                 return DUK_DOUBLE_INFINITY;
62131                         }
62132                 }
62133         } else if (cx == DUK_FP_NAN) {
62134                 if (y == 0.0) {
62135                         /* NaN ** +/- 0 should always be 1, but is NaN on
62136                          * at least some Cygwin/MinGW versions.
62137                          */
62138                         return 1.0;
62139                 }
62140         }
62141 #else
62142         /* Some ISO C assumptions. */
62143         DUK_ASSERT(DUK_POW(DUK_DOUBLE_NAN, 0.0) == 1.0);
62144         DUK_ASSERT(DUK_ISINF(DUK_POW(0.0, -1.0)) && DUK_SIGNBIT(DUK_POW(0.0, -1.0)) == 0);
62145         DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -2.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -2.0)) == 0);
62146         DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -3.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -3.0)) != 0);
62147 #endif
62148
62149         return DUK_POW(x, y);
62150
62151  ret_nan:
62152         return DUK_DOUBLE_NAN;
62153 }
62154 #line 1 "duk_js_call.c"
62155 /*
62156  *  Call handling.
62157  *
62158  *  duk_handle_call_unprotected():
62159  *
62160  *    - Unprotected call to ECMAScript or Duktape/C function, from native
62161  *      code or bytecode executor.
62162  *
62163  *    - Also handles Ecma-to-Ecma calls which reuses a currently running
62164  *      executor instance to avoid native recursion.  Call setup is done
62165  *      normally, but just before calling the bytecode executor a special
62166  *      return code is used to indicate that a calling executor is reused.
62167  *
62168  *    - Also handles tailcalls, i.e. reuse of current duk_activation.
62169  *
62170  *    - Also handles setup for initial Duktape.Thread.resume().
62171  *
62172  *  duk_handle_safe_call():
62173  *
62174  *    - Protected C call within current activation.
62175  *
62176  *  setjmp() and local variables have a nasty interaction, see execution.rst;
62177  *  non-volatile locals modified after setjmp() call are not guaranteed to
62178  *  keep their value and can cause compiler or compiler version specific
62179  *  difficult to replicate issues.
62180  *
62181  *  See 'execution.rst'.
62182  */
62183
62184 /* #include duk_internal.h -> already included */
62185
62186 /* XXX: heap->error_not_allowed for success path too? */
62187
62188 /*
62189  *  Limit check helpers.
62190  */
62191
62192 /* Allow headroom for calls during error augmentation (see GH-191).
62193  * We allow space for 10 additional recursions, with one extra
62194  * for, e.g. a print() call at the deepest level, and an extra
62195  * +1 for protected call wrapping.
62196  */
62197 #define DUK__AUGMENT_CALL_RELAX_COUNT  (10 + 2)
62198
62199 DUK_LOCAL DUK_NOINLINE void duk__call_c_recursion_limit_check_slowpath(duk_hthread *thr) {
62200         /* When augmenting an error, the effective limit is a bit higher.
62201          * Check for it only if the fast path check fails.
62202          */
62203 #if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
62204         if (thr->heap->augmenting_error) {
62205                 if (thr->heap->call_recursion_depth < thr->heap->call_recursion_limit + DUK__AUGMENT_CALL_RELAX_COUNT) {
62206                         DUK_D(DUK_DPRINT("C recursion limit reached but augmenting error and within relaxed limit"));
62207                         return;
62208                 }
62209         }
62210 #endif
62211
62212         DUK_D(DUK_DPRINT("call prevented because C recursion limit reached"));
62213         DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
62214         DUK_WO_NORETURN(return;);
62215 }
62216
62217 DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_c_recursion_limit_check(duk_hthread *thr) {
62218         DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
62219         DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
62220
62221         /* This check is forcibly inlined because it's very cheap and almost
62222          * always passes.  The slow path is forcibly noinline.
62223          */
62224         if (DUK_LIKELY(thr->heap->call_recursion_depth < thr->heap->call_recursion_limit)) {
62225                 return;
62226         }
62227
62228         duk__call_c_recursion_limit_check_slowpath(thr);
62229 }
62230
62231 DUK_LOCAL DUK_NOINLINE void duk__call_callstack_limit_check_slowpath(duk_hthread *thr) {
62232         /* When augmenting an error, the effective limit is a bit higher.
62233          * Check for it only if the fast path check fails.
62234          */
62235 #if defined(DUK_USE_AUGMENT_ERROR_THROW) || defined(DUK_USE_AUGMENT_ERROR_CREATE)
62236         if (thr->heap->augmenting_error) {
62237                 if (thr->callstack_top < DUK_USE_CALLSTACK_LIMIT + DUK__AUGMENT_CALL_RELAX_COUNT) {
62238                         DUK_D(DUK_DPRINT("call stack limit reached but augmenting error and within relaxed limit"));
62239                         return;
62240                 }
62241         }
62242 #endif
62243
62244         /* XXX: error message is a bit misleading: we reached a recursion
62245          * limit which is also essentially the same as a C callstack limit
62246          * (except perhaps with some relaxed threading assumptions).
62247          */
62248         DUK_D(DUK_DPRINT("call prevented because call stack limit reached"));
62249         DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
62250         DUK_WO_NORETURN(return;);
62251 }
62252
62253 DUK_LOCAL DUK_ALWAYS_INLINE void duk__call_callstack_limit_check(duk_hthread *thr) {
62254         /* This check is forcibly inlined because it's very cheap and almost
62255          * always passes.  The slow path is forcibly noinline.
62256          */
62257         if (DUK_LIKELY(thr->callstack_top < DUK_USE_CALLSTACK_LIMIT)) {
62258                 return;
62259         }
62260
62261         duk__call_callstack_limit_check_slowpath(thr);
62262 }
62263
62264 /*
62265  *  Interrupt counter fixup (for development only).
62266  */
62267
62268 #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
62269 DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) {
62270         /* Currently the bytecode executor and executor interrupt
62271          * instruction counts are off because we don't execute the
62272          * interrupt handler when we're about to exit from the initial
62273          * user call into Duktape.
62274          *
62275          * If we were to execute the interrupt handler here, the counts
62276          * would match.  You can enable this block manually to check
62277          * that this is the case.
62278          */
62279
62280         DUK_ASSERT(thr != NULL);
62281         DUK_ASSERT(thr->heap != NULL);
62282
62283 #if defined(DUK_USE_INTERRUPT_DEBUG_FIXUP)
62284         if (entry_curr_thread == NULL) {
62285                 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
62286                 thr->heap->inst_count_interrupt += thr->interrupt_init;
62287                 DUK_DD(DUK_DDPRINT("debug test: updated interrupt count on exit to "
62288                                    "user code, instruction counts: executor=%ld, interrupt=%ld",
62289                                    (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
62290                 DUK_ASSERT(thr->heap->inst_count_exec == thr->heap->inst_count_interrupt);
62291         }
62292 #else
62293         DUK_UNREF(thr);
62294         DUK_UNREF(entry_curr_thread);
62295 #endif
62296 }
62297 #endif
62298
62299 /*
62300  *  Arguments object creation.
62301  *
62302  *  Creating arguments objects involves many small details, see E5 Section
62303  *  10.6 for the specific requirements.  Much of the arguments object exotic
62304  *  behavior is implemented in duk_hobject_props.c, and is enabled by the
62305  *  object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
62306  */
62307
62308 DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
62309                                             duk_hobject *func,
62310                                             duk_hobject *varenv,
62311                                             duk_idx_t idx_args) {
62312         duk_hobject *arg;          /* 'arguments' */
62313         duk_hobject *formals;      /* formals for 'func' (may be NULL if func is a C function) */
62314         duk_idx_t i_arg;
62315         duk_idx_t i_map;
62316         duk_idx_t i_mappednames;
62317         duk_idx_t i_formals;
62318         duk_idx_t i_argbase;
62319         duk_idx_t n_formals;
62320         duk_idx_t idx;
62321         duk_idx_t num_stack_args;
62322         duk_bool_t need_map;
62323
62324         DUK_ASSERT(thr != NULL);
62325         DUK_ASSERT(func != NULL);
62326         DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
62327         DUK_ASSERT(varenv != NULL);
62328
62329         /* [ ... func this arg1(@idx_args) ... argN envobj ]
62330          * [ arg1(@idx_args) ... argN envobj ] (for tailcalls)
62331          */
62332
62333         need_map = 0;
62334
62335         i_argbase = idx_args;
62336         num_stack_args = duk_get_top(thr) - i_argbase - 1;
62337         DUK_ASSERT(i_argbase >= 0);
62338         DUK_ASSERT(num_stack_args >= 0);
62339
62340         duk_push_hobject(thr, func);
62341         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FORMALS);
62342         formals = duk_get_hobject(thr, -1);
62343         if (formals) {
62344                 n_formals = (duk_idx_t) duk_get_length(thr, -1);
62345         } else {
62346                 /* This shouldn't happen without tampering of internal
62347                  * properties: if a function accesses 'arguments', _Formals
62348                  * is kept.  Check for the case anyway in case internal
62349                  * properties have been modified manually.
62350                  */
62351                 DUK_D(DUK_DPRINT("_Formals is undefined when creating arguments, use n_formals == 0"));
62352                 n_formals = 0;
62353         }
62354         duk_remove_m2(thr);  /* leave formals on stack for later use */
62355         i_formals = duk_require_top_index(thr);
62356
62357         DUK_ASSERT(n_formals >= 0);
62358         DUK_ASSERT(formals != NULL || n_formals == 0);
62359
62360         DUK_DDD(DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%ld",
62361                              (duk_heaphdr *) func, (duk_heaphdr *) formals,
62362                              (long) n_formals));
62363
62364         /* [ ... formals ] */
62365
62366         /*
62367          *  Create required objects:
62368          *    - 'arguments' object: array-like, but not an array
62369          *    - 'map' object: internal object, tied to 'arguments'
62370          *    - 'mappedNames' object: temporary value used during construction
62371          */
62372
62373         arg = duk_push_object_helper(thr,
62374                                      DUK_HOBJECT_FLAG_EXTENSIBLE |
62375                                      DUK_HOBJECT_FLAG_FASTREFS |
62376                                      DUK_HOBJECT_FLAG_ARRAY_PART |
62377                                      DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
62378                                      DUK_BIDX_OBJECT_PROTOTYPE);
62379         DUK_ASSERT(arg != NULL);
62380         (void) duk_push_object_helper(thr,
62381                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
62382                                       DUK_HOBJECT_FLAG_FASTREFS |
62383                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
62384                                       -1);  /* no prototype */
62385         (void) duk_push_object_helper(thr,
62386                                       DUK_HOBJECT_FLAG_EXTENSIBLE |
62387                                       DUK_HOBJECT_FLAG_FASTREFS |
62388                                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
62389                                       -1);  /* no prototype */
62390         i_arg = duk_get_top(thr) - 3;
62391         i_map = i_arg + 1;
62392         i_mappednames = i_arg + 2;
62393
62394         /* [ ... formals arguments map mappedNames ] */
62395
62396         DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
62397                              "arguments at index %ld -> %!O "
62398                              "map at index %ld -> %!O "
62399                              "mappednames at index %ld -> %!O",
62400                              (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg),
62401                              (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map),
62402                              (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames)));
62403
62404         /*
62405          *  Init arguments properties, map, etc.
62406          */
62407
62408         duk_push_int(thr, num_stack_args);
62409         duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
62410
62411         /*
62412          *  Init argument related properties.
62413          */
62414
62415         /* step 11 */
62416         idx = num_stack_args - 1;
62417         while (idx >= 0) {
62418                 DUK_DDD(DUK_DDDPRINT("arg idx %ld, argbase=%ld, argidx=%ld",
62419                                      (long) idx, (long) i_argbase, (long) (i_argbase + idx)));
62420
62421                 DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx));
62422                 duk_dup(thr, i_argbase + idx);
62423                 duk_xdef_prop_index_wec(thr, i_arg, (duk_uarridx_t) idx);
62424                 DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx));
62425
62426                 /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
62427                 if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) {
62428                         DUK_ASSERT(formals != NULL);
62429
62430                         DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)",
62431                                              (long) idx, (long) n_formals));
62432
62433                         duk_get_prop_index(thr, i_formals, (duk_uarridx_t) idx);
62434                         DUK_ASSERT(duk_is_string(thr, -1));
62435
62436                         duk_dup_top(thr);  /* [ ... name name ] */
62437
62438                         if (!duk_has_prop(thr, i_mappednames)) {
62439                                 /* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
62440                                  * differs from the reference model
62441                                  */
62442
62443                                 /* [ ... name ] */
62444
62445                                 need_map = 1;
62446
62447                                 DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld",
62448                                                      (const char *) duk_get_string(thr, -1),
62449                                                      (long) idx));
62450                                 duk_dup_top(thr);                      /* name */
62451                                 (void) duk_push_uint_to_hstring(thr, (duk_uint_t) idx);  /* index */
62452                                 duk_xdef_prop_wec(thr, i_mappednames);  /* out of spec, must be configurable */
62453
62454                                 DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s",
62455                                                      (long) idx,
62456                                                      duk_get_string(thr, -1)));
62457                                 duk_dup_top(thr);         /* name */
62458                                 duk_xdef_prop_index_wec(thr, i_map, (duk_uarridx_t) idx);  /* out of spec, must be configurable */
62459                         } else {
62460                                 /* duk_has_prop() popped the second 'name' */
62461                         }
62462
62463                         /* [ ... name ] */
62464                         duk_pop(thr);  /* pop 'name' */
62465                 }
62466
62467                 idx--;
62468         }
62469
62470         DUK_DDD(DUK_DDDPRINT("actual arguments processed"));
62471
62472         /* step 12 */
62473         if (need_map) {
62474                 DUK_DDD(DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object"));
62475
62476                 /* should never happen for a strict callee */
62477                 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
62478
62479                 duk_dup(thr, i_map);
62480                 duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE);  /* out of spec, don't care */
62481
62482                 /* The variable environment for magic variable bindings needs to be
62483                  * given by the caller and recorded in the arguments object.
62484                  *
62485                  * See E5 Section 10.6, the creation of setters/getters.
62486                  *
62487                  * The variable environment also provides access to the callee, so
62488                  * an explicit (internal) callee property is not needed.
62489                  */
62490
62491                 duk_push_hobject(thr, varenv);
62492                 duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE);  /* out of spec, don't care */
62493         }
62494
62495         /* steps 13-14 */
62496         if (DUK_HOBJECT_HAS_STRICT(func)) {
62497                 /* Callee/caller are throwers and are not deletable etc.  They
62498                  * could be implemented as virtual properties, but currently
62499                  * there is no support for virtual properties which are accessors
62500                  * (only plain virtual properties).  This would not be difficult
62501                  * to change in duk_hobject_props, but we can make the throwers
62502                  * normal, concrete properties just as easily.
62503                  *
62504                  * Note that the specification requires that the *same* thrower
62505                  * built-in object is used here!  See E5 Section 10.6 main
62506                  * algoritm, step 14, and Section 13.2.3 which describes the
62507                  * thrower.  See test case test-arguments-throwers.js.
62508                  */
62509
62510                 DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
62511
62512                 duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLER);
62513                 duk_xdef_prop_stridx_thrower(thr, i_arg, DUK_STRIDX_CALLEE);
62514         } else {
62515                 DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value"));
62516                 duk_push_hobject(thr, func);
62517                 duk_xdef_prop_stridx(thr, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
62518         }
62519
62520         /* set exotic behavior only after we're done */
62521         if (need_map) {
62522                 /* Exotic behaviors are only enabled for arguments objects
62523                  * which have a parameter map (see E5 Section 10.6 main
62524                  * algorithm, step 12).
62525                  *
62526                  * In particular, a non-strict arguments object with no
62527                  * mapped formals does *NOT* get exotic behavior, even
62528                  * for e.g. "caller" property.  This seems counterintuitive
62529                  * but seems to be the case.
62530                  */
62531
62532                 /* cannot be strict (never mapped variables) */
62533                 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
62534
62535                 DUK_DDD(DUK_DDDPRINT("enabling exotic behavior for arguments object"));
62536                 DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(arg);
62537         } else {
62538                 DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
62539         }
62540
62541         DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
62542                              "arguments at index %ld -> %!O "
62543                              "map at index %ld -> %!O "
62544                              "mappednames at index %ld -> %!O",
62545                              (long) i_arg, (duk_heaphdr *) duk_get_hobject(thr, i_arg),
62546                              (long) i_map, (duk_heaphdr *) duk_get_hobject(thr, i_map),
62547                              (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(thr, i_mappednames)));
62548
62549         /* [ args(n) envobj formals arguments map mappednames ] */
62550
62551         duk_pop_2(thr);
62552         duk_remove_m2(thr);
62553
62554         /* [ args(n) envobj arguments ] */
62555 }
62556
62557 /* Helper for creating the arguments object and adding it to the env record
62558  * on top of the value stack.
62559  */
62560 DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
62561                                                duk_hobject *func,
62562                                                duk_hobject *env,
62563                                                duk_idx_t idx_args) {
62564         DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
62565
62566         DUK_ASSERT(thr != NULL);
62567         DUK_ASSERT(func != NULL);
62568         DUK_ASSERT(env != NULL);
62569         DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
62570
62571         /* [ ... arg1 ... argN envobj ] */
62572
62573         duk__create_arguments_object(thr,
62574                                      func,
62575                                      env,
62576                                      idx_args);
62577
62578         /* [ ... arg1 ... argN envobj argobj ] */
62579
62580         duk_xdef_prop_stridx_short(thr,
62581                                    -2,
62582                                    DUK_STRIDX_LC_ARGUMENTS,
62583                                    DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E :   /* strict: non-deletable, non-writable */
62584                                                                   DUK_PROPDESC_FLAGS_WE);  /* non-strict: non-deletable, writable */
62585         /* [ ... arg1 ... argN envobj ] */
62586 }
62587
62588 /*
62589  *  Helpers for constructor call handling.
62590  *
62591  *  There are two [[Construct]] operations in the specification:
62592  *
62593  *    - E5 Section 13.2.2: for Function objects
62594  *    - E5 Section 15.3.4.5.2: for "bound" Function objects
62595  *
62596  *  The chain of bound functions is resolved in Section 15.3.4.5.2,
62597  *  with arguments "piling up" until the [[Construct]] internal
62598  *  method is called on the final, actual Function object.  Note
62599  *  that the "prototype" property is looked up *only* from the
62600  *  final object, *before* calling the constructor.
62601  *
62602  *  Since Duktape 2.2 bound functions are represented with the
62603  *  duk_hboundfunc internal type, and bound function chains are
62604  *  collapsed when a bound function is created.  As a result, the
62605  *  direct target of a duk_hboundfunc is always non-bound and the
62606  *  this/argument lists have been resolved.
62607  *
62608  *  When constructing new Array instances, an unnecessary object is
62609  *  created and discarded now: the standard [[Construct]] creates an
62610  *  object, and calls the Array constructor.  The Array constructor
62611  *  returns an Array instance, which is used as the result value for
62612  *  the "new" operation; the object created before the Array constructor
62613  *  call is discarded.
62614  *
62615  *  This would be easy to fix, e.g. by knowing that the Array constructor
62616  *  will always create a replacement object and skip creating the fallback
62617  *  object in that case.
62618  */
62619
62620 /* Update default instance prototype for constructor call. */
62621 DUK_LOCAL void duk__update_default_instance_proto(duk_hthread *thr, duk_idx_t idx_func) {
62622         duk_hobject *proto;
62623         duk_hobject *fallback;
62624
62625         DUK_ASSERT(duk_is_constructable(thr, idx_func));
62626
62627         duk_get_prop_stridx_short(thr, idx_func, DUK_STRIDX_PROTOTYPE);
62628         proto = duk_get_hobject(thr, -1);
62629         if (proto == NULL) {
62630                 DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
62631                                      "-> leave standard Object prototype as fallback prototype"));
62632         } else {
62633                 DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
62634                                      "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
62635                 /* Original fallback (default instance) is untouched when
62636                  * resolving bound functions etc.
62637                  */
62638                 fallback = duk_known_hobject(thr, idx_func + 1);
62639                 DUK_ASSERT(fallback != NULL);
62640                 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
62641         }
62642         duk_pop(thr);
62643 }
62644
62645 /* Postprocess: return value special handling, error augmentation. */
62646 DUK_INTERNAL void duk_call_construct_postprocess(duk_hthread *thr, duk_small_uint_t proxy_invariant) {
62647         /* Use either fallback (default instance) or retval depending
62648          * on retval type.  Needs to be called before unwind because
62649          * the default instance is read from the current (immutable)
62650          * 'this' binding.
62651          *
62652          * For Proxy 'construct' calls the return value must be an
62653          * Object (we accept object-like values like buffers and
62654          * lightfuncs too).  If not, TypeError.
62655          */
62656         if (duk_check_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT |
62657                                          DUK_TYPE_MASK_BUFFER |
62658                                          DUK_TYPE_MASK_LIGHTFUNC)) {
62659                 DUK_DDD(DUK_DDDPRINT("replacement value"));
62660         } else {
62661                 if (DUK_UNLIKELY(proxy_invariant != 0U)) {
62662                         /* Proxy 'construct' return value invariant violated. */
62663                         DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
62664                         DUK_WO_NORETURN(return;);
62665                 }
62666                 /* XXX: direct value stack access */
62667                 duk_pop(thr);
62668                 duk_push_this(thr);
62669         }
62670
62671 #if defined(DUK_USE_AUGMENT_ERROR_CREATE)
62672         /* Augment created errors upon creation, not when they are thrown or
62673          * rethrown.  __FILE__ and __LINE__ are not desirable here; the call
62674          * stack reflects the caller which is correct.  Skip topmost, unwound
62675          * activation when creating a traceback.  If thr->ptr_curr_pc was !=
62676          * NULL we'd need to sync the current PC so that the traceback comes
62677          * out right; however it is always synced here so just assert for it.
62678          */
62679         DUK_ASSERT(thr->ptr_curr_pc == NULL);
62680         duk_err_augment_error_create(thr, thr, NULL, 0, DUK_AUGMENT_FLAG_NOBLAME_FILELINE |
62681                                                         DUK_AUGMENT_FLAG_SKIP_ONE);
62682 #endif
62683 }
62684
62685 /*
62686  *  Helper for handling a bound function when a call is being made.
62687  *
62688  *  Assumes that bound function chains have been "collapsed" so that either
62689  *  the target is non-bound or there is one bound function that points to a
62690  *  nonbound target.
62691  *
62692  *  Prepends the bound arguments to the value stack (at idx_func + 2).
62693  *  The 'this' binding is also updated if necessary (at idx_func + 1).
62694  *  Note that for constructor calls the 'this' binding is never updated by
62695  *  [[BoundThis]].
62696  */
62697
62698 DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
62699                                                 duk_idx_t idx_func,
62700                                                 duk_bool_t is_constructor_call) {
62701         duk_tval *tv_func;
62702         duk_hobject *func;
62703         duk_idx_t len;
62704
62705         DUK_ASSERT(thr != NULL);
62706
62707         /* On entry, item at idx_func is a bound, non-lightweight function,
62708          * but we don't rely on that below.
62709          */
62710
62711         DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
62712
62713         tv_func = duk_require_tval(thr, idx_func);
62714         DUK_ASSERT(tv_func != NULL);
62715
62716         if (DUK_TVAL_IS_OBJECT(tv_func)) {
62717                 func = DUK_TVAL_GET_OBJECT(tv_func);
62718
62719                 /* XXX: separate helper function, out of fast path? */
62720                 if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
62721                         duk_hboundfunc *h_bound;
62722                         duk_tval *tv_args;
62723                         duk_tval *tv_gap;
62724
62725                         h_bound = (duk_hboundfunc *) (void *) func;
62726                         tv_args = h_bound->args;
62727                         len = h_bound->nargs;
62728                         DUK_ASSERT(len == 0 || tv_args != NULL);
62729
62730                         DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p: %!T",
62731                                              (void *) DUK_TVAL_GET_OBJECT(tv_func), tv_func));
62732
62733                         /* [ ... func this arg1 ... argN ] */
62734
62735                         if (is_constructor_call) {
62736                                 /* See: tests/ecmascript/test-spec-bound-constructor.js */
62737                                 DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
62738                         } else {
62739                                 /* XXX: duk_replace_tval */
62740                                 duk_push_tval(thr, &h_bound->this_binding);
62741                                 duk_replace(thr, idx_func + 1);  /* idx_this = idx_func + 1 */
62742                         }
62743
62744                         /* [ ... func this arg1 ... argN ] */
62745
62746                         duk_require_stack(thr, len);
62747
62748                         tv_gap = duk_reserve_gap(thr, idx_func + 2, len);
62749                         duk_copy_tvals_incref(thr, tv_gap, tv_args, (duk_size_t) len);
62750
62751                         /* [ ... func this <bound args> arg1 ... argN ] */
62752
62753                         duk_push_tval(thr, &h_bound->target);
62754                         duk_replace(thr, idx_func);  /* replace in stack */
62755
62756                         DUK_DDD(DUK_DDDPRINT("bound function handled, idx_func=%ld, curr func=%!T",
62757                                              (long) idx_func, duk_get_tval(thr, idx_func)));
62758                 }
62759         } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
62760                 /* Lightweight function: never bound, so terminate. */
62761                 ;
62762         } else {
62763                 /* Shouldn't happen, so ugly error is enough. */
62764                 DUK_ERROR_INTERNAL(thr);
62765                 DUK_WO_NORETURN(return;);
62766         }
62767
62768         DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
62769
62770         DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(thr, idx_func)));
62771
62772 #if defined(DUK_USE_ASSERTIONS)
62773         tv_func = duk_require_tval(thr, idx_func);
62774         DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
62775         if (DUK_TVAL_IS_OBJECT(tv_func)) {
62776                 func = DUK_TVAL_GET_OBJECT(tv_func);
62777                 DUK_ASSERT(func != NULL);
62778                 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
62779                 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func) ||
62780                            DUK_HOBJECT_HAS_NATFUNC(func));
62781         }
62782 #endif
62783 }
62784
62785 /*
62786  *  Helper for inline handling of .call(), .apply(), and .construct().
62787  */
62788
62789 DUK_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) {
62790 #if defined(DUK_USE_ASSERTIONS)
62791         duk_c_function natfunc;
62792 #endif
62793         duk_tval *tv_args;
62794
62795         DUK_ASSERT(func != NULL);
62796         DUK_ASSERT((*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0);  /* Caller. */
62797
62798 #if defined(DUK_USE_ASSERTIONS)
62799         natfunc = ((duk_hnatfunc *) func)->func;
62800         DUK_ASSERT(natfunc != NULL);
62801 #endif
62802
62803         /* On every round of function resolution at least target function and
62804          * 'this' binding are set.  We can assume that here, and must guarantee
62805          * it on exit.  Value stack reserve is extended for bound function and
62806          * .apply() unpacking so we don't need to extend it here when we need a
62807          * few slots.
62808          */
62809         DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
62810
62811         /* Handle native 'eval' specially.  A direct eval check is only made
62812          * for the first resolution attempt; e.g. a bound eval call is -not-
62813          * a direct eval call.
62814          */
62815         if (DUK_UNLIKELY(((duk_hnatfunc *) func)->magic == 15)) {
62816                 /* For now no special handling except for direct eval
62817                  * detection.
62818                  */
62819                 DUK_ASSERT(((duk_hnatfunc *) func)->func == duk_bi_global_object_eval);
62820                 if (first && (*call_flags & DUK_CALL_FLAG_CALLED_AS_EVAL)) {
62821                         *call_flags = (*call_flags & ~DUK_CALL_FLAG_CALLED_AS_EVAL) | DUK_CALL_FLAG_DIRECT_EVAL;
62822                 }
62823                 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
62824                 return 1;  /* stop resolving */
62825         }
62826
62827         /* Handle special functions based on the DUK_HOBJECT_FLAG_SPECIAL_CALL
62828          * flag; their magic value is used for switch-case.
62829          *
62830          * NOTE: duk_unpack_array_like() reserves value stack space
62831          * for the result values (unlike most other value stack calls).
62832          */
62833         switch (((duk_hnatfunc *) func)->magic) {
62834         case 0: {  /* 0=Function.prototype.call() */
62835                 /* Value stack:
62836                  * idx_func + 0: Function.prototype.call()  [removed]
62837                  * idx_func + 1: this binding for .call (target function)
62838                  * idx_func + 2: 1st argument to .call, desired 'this' binding
62839                  * idx_func + 3: 2nd argument to .call, desired 1st argument for ultimate target
62840                  * ...
62841                  *
62842                  * Remove idx_func + 0 to get:
62843                  * idx_func + 0: target function
62844                  * idx_func + 1: this binding
62845                  * idx_func + 2: call arguments
62846                  * ...
62847                  */
62848                 DUK_ASSERT(natfunc == duk_bi_function_prototype_call);
62849                 duk_remove_unsafe(thr, idx_func);
62850                 tv_args = thr->valstack_bottom + idx_func + 2;
62851                 if (thr->valstack_top < tv_args) {
62852                         DUK_ASSERT(tv_args <= thr->valstack_end);
62853                         thr->valstack_top = tv_args;  /* at least target function and 'this' binding present */
62854                 }
62855                 break;
62856         }
62857         case 1: {  /* 1=Function.prototype.apply() */
62858                 /* Value stack:
62859                  * idx_func + 0: Function.prototype.apply()  [removed]
62860                  * idx_func + 1: this binding for .apply (target function)
62861                  * idx_func + 2: 1st argument to .apply, desired 'this' binding
62862                  * idx_func + 3: 2nd argument to .apply, argArray
62863                  * [anything after this MUST be ignored]
62864                  *
62865                  * Remove idx_func + 0 and unpack the argArray to get:
62866                  * idx_func + 0: target function
62867                  * idx_func + 1: this binding
62868                  * idx_func + 2: call arguments
62869                  * ...
62870                  */
62871                 DUK_ASSERT(natfunc == duk_bi_function_prototype_apply);
62872                 duk_remove_unsafe(thr, idx_func);
62873                 goto apply_shared;
62874         }
62875 #if defined(DUK_USE_REFLECT_BUILTIN)
62876         case 2: {  /* 2=Reflect.apply() */
62877                 /* Value stack:
62878                  * idx_func + 0: Reflect.apply()  [removed]
62879                  * idx_func + 1: this binding for .apply (ignored, usually Reflect)  [removed]
62880                  * idx_func + 2: 1st argument to .apply, target function
62881                  * idx_func + 3: 2nd argument to .apply, desired 'this' binding
62882                  * idx_func + 4: 3rd argument to .apply, argArray
62883                  * [anything after this MUST be ignored]
62884                  *
62885                  * Remove idx_func + 0 and idx_func + 1, and unpack the argArray to get:
62886                  * idx_func + 0: target function
62887                  * idx_func + 1: this binding
62888                  * idx_func + 2: call arguments
62889                  * ...
62890                  */
62891                 DUK_ASSERT(natfunc == duk_bi_reflect_apply);
62892                 duk_remove_n_unsafe(thr, idx_func, 2);
62893                 goto apply_shared;
62894         }
62895         case 3: {  /* 3=Reflect.construct() */
62896                 /* Value stack:
62897                  * idx_func + 0: Reflect.construct()  [removed]
62898                  * idx_func + 1: this binding for .construct (ignored, usually Reflect)  [removed]
62899                  * idx_func + 2: 1st argument to .construct, target function
62900                  * idx_func + 3: 2nd argument to .construct, argArray
62901                  * idx_func + 4: 3rd argument to .construct, newTarget
62902                  * [anything after this MUST be ignored]
62903                  *
62904                  * Remove idx_func + 0 and idx_func + 1, unpack the argArray,
62905                  * and insert default instance (prototype not yet updated), to get:
62906                  * idx_func + 0: target function
62907                  * idx_func + 1: this binding (default instance)
62908                  * idx_func + 2: constructor call arguments
62909                  * ...
62910                  *
62911                  * Call flags must be updated to reflect the fact that we're
62912                  * now dealing with a constructor call, and e.g. the 'this'
62913                  * binding cannot be overwritten if the target is bound.
62914                  *
62915                  * newTarget is checked but not yet passed onwards.
62916                  */
62917
62918                 duk_idx_t top;
62919
62920                 DUK_ASSERT(natfunc == duk_bi_reflect_construct);
62921                 *call_flags |= DUK_CALL_FLAG_CONSTRUCT;
62922                 duk_remove_n_unsafe(thr, idx_func, 2);
62923                 top = duk_get_top(thr);
62924                 if (!duk_is_constructable(thr, idx_func)) {
62925                         /* Target constructability must be checked before
62926                          * unpacking argArray (which may cause side effects).
62927                          * Just return; caller will throw the error.
62928                          */
62929                         duk_set_top_unsafe(thr, idx_func + 2);  /* satisfy asserts */
62930                         break;
62931                 }
62932                 duk_push_object(thr);
62933                 duk_insert(thr, idx_func + 1);  /* default instance */
62934
62935                 /* [ ... func default_instance argArray newTarget? ] */
62936
62937                 top = duk_get_top(thr);
62938                 if (top < idx_func + 3) {
62939                         /* argArray is a mandatory argument for Reflect.construct(). */
62940                         DUK_ERROR_TYPE_INVALID_ARGS(thr);
62941                         DUK_WO_NORETURN(return 0;);
62942                 }
62943                 if (top > idx_func + 3) {
62944                         if (!duk_strict_equals(thr, idx_func, idx_func + 3)) {
62945                                 /* XXX: [[Construct]] newTarget currently unsupported */
62946                                 DUK_ERROR_UNSUPPORTED(thr);
62947                                 DUK_WO_NORETURN(return 0;);
62948                         }
62949                         duk_set_top_unsafe(thr, idx_func + 3);  /* remove any args beyond argArray */
62950                 }
62951                 DUK_ASSERT(duk_get_top(thr) == idx_func + 3);
62952                 DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2));
62953                 (void) duk_unpack_array_like(thr, idx_func + 2);  /* XXX: should also remove target to be symmetric with duk_pack()? */
62954                 duk_remove(thr, idx_func + 2);
62955                 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
62956                 break;
62957         }
62958 #endif  /* DUK_USE_REFLECT_BUILTIN */
62959         default: {
62960                 DUK_ASSERT(0);
62961                 DUK_UNREACHABLE();
62962         }
62963         }
62964
62965         DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
62966         return 0;  /* keep resolving */
62967
62968  apply_shared:
62969         tv_args = thr->valstack_bottom + idx_func + 2;
62970         if (thr->valstack_top <= tv_args) {
62971                 DUK_ASSERT(tv_args <= thr->valstack_end);
62972                 thr->valstack_top = tv_args;  /* at least target func and 'this' binding present */
62973                 /* No need to check for argArray. */
62974         } else {
62975                 DUK_ASSERT(duk_get_top(thr) >= idx_func + 3);  /* idx_func + 2 covered above */
62976                 if (thr->valstack_top > tv_args + 1) {
62977                         duk_set_top_unsafe(thr, idx_func + 3);  /* remove any args beyond argArray */
62978                 }
62979                 DUK_ASSERT(duk_is_valid_index(thr, idx_func + 2));
62980                 if (!duk_is_callable(thr, idx_func)) {
62981                         /* Avoid unpack side effects if the target isn't callable.
62982                          * Calling code will throw the actual error.
62983                          */
62984                 } else {
62985                         (void) duk_unpack_array_like(thr, idx_func + 2);
62986                         duk_remove(thr, idx_func + 2);
62987                 }
62988         }
62989         DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
62990         return 0;  /* keep resolving */
62991 }
62992
62993 /*
62994  *  Helper for Proxy handling.
62995  */
62996
62997 #if defined(DUK_USE_ES6_PROXY)
62998 DUK_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) {
62999         duk_bool_t rc;
63000
63001         /* Value stack:
63002          * idx_func + 0: Proxy object
63003          * idx_func + 1: this binding for call
63004          * idx_func + 2: 1st argument for call
63005          * idx_func + 3: 2nd argument for call
63006          * ...
63007          *
63008          * If Proxy doesn't have a trap for the call ('apply' or 'construct'),
63009          * replace Proxy object with target object.
63010          *
63011          * If we're dealing with a normal call and the Proxy has an 'apply'
63012          * trap, manipulate value stack to:
63013          *
63014          * idx_func + 0: trap
63015          * idx_func + 1: Proxy's handler
63016          * idx_func + 2: Proxy's target
63017          * idx_func + 3: this binding for call (from idx_func + 1)
63018          * idx_func + 4: call arguments packed to an array
63019          *
63020          * If we're dealing with a constructor call and the Proxy has a
63021          * 'construct' trap, manipulate value stack to:
63022          *
63023          * idx_func + 0: trap
63024          * idx_func + 1: Proxy's handler
63025          * idx_func + 2: Proxy's target
63026          * idx_func + 3: call arguments packed to an array
63027          * idx_func + 4: newTarget == Proxy object here
63028          *
63029          * As we don't yet have proper newTarget support, the newTarget at
63030          * idx_func + 3 is just the original constructor being called, i.e.
63031          * the Proxy object (not the target).  Note that the default instance
63032          * (original 'this' binding) is dropped and ignored.
63033          */
63034
63035         duk_push_hobject(thr, h_proxy->handler);
63036         rc = duk_get_prop_stridx_short(thr, -1, (*call_flags & DUK_CALL_FLAG_CONSTRUCT) ? DUK_STRIDX_CONSTRUCT : DUK_STRIDX_APPLY);
63037         if (rc == 0) {
63038                 /* Not found, continue to target.  If this is a construct
63039                  * call, update default instance prototype using the Proxy,
63040                  * not the target.
63041                  */
63042                 if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
63043                         if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) {
63044                                 *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED;
63045                                 duk__update_default_instance_proto(thr, idx_func);
63046                         }
63047                 }
63048                 duk_pop_2(thr);
63049                 duk_push_hobject(thr, h_proxy->target);
63050                 duk_replace(thr, idx_func);
63051                 return;
63052         }
63053
63054         /* Here we must be careful not to replace idx_func while
63055          * h_proxy is still needed, otherwise h_proxy may become
63056          * dangling.  This could be improved e.g. using a
63057          * duk_pack_slice() with a freeform slice.
63058          */
63059
63060         /* Here:
63061          * idx_func + 0: Proxy object
63062          * idx_func + 1: this binding for call
63063          * idx_func + 2: 1st argument for call
63064          * idx_func + 3: 2nd argument for call
63065          * ...
63066          * idx_func + N: handler
63067          * idx_func + N + 1: trap
63068          */
63069
63070         duk_insert(thr, idx_func + 1);
63071         duk_insert(thr, idx_func + 2);
63072         duk_push_hobject(thr, h_proxy->target);
63073         duk_insert(thr, idx_func + 3);
63074         duk_pack(thr, duk_get_top(thr) - (idx_func + 5));
63075
63076         /* Here:
63077          * idx_func + 0: Proxy object
63078          * idx_func + 1: trap
63079          * idx_func + 2: Proxy's handler
63080          * idx_func + 3: Proxy's target
63081          * idx_func + 4: this binding for call
63082          * idx_func + 5: arguments array
63083          */
63084         DUK_ASSERT(duk_get_top(thr) == idx_func + 6);
63085
63086         if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
63087                 *call_flags |= DUK_CALL_FLAG_CONSTRUCT_PROXY;  /* Enable 'construct' trap return invariant check. */
63088                 *call_flags &= ~(DUK_CALL_FLAG_CONSTRUCT);     /* Resume as non-constructor call to the trap. */
63089
63090                 /* 'apply' args: target, thisArg, argArray
63091                  * 'construct' args: target, argArray, newTarget
63092                  */
63093                 duk_remove(thr, idx_func + 4);
63094                 duk_push_hobject(thr, (duk_hobject *) h_proxy);
63095         }
63096
63097         /* Finalize value stack layout by removing Proxy reference. */
63098         duk_remove(thr, idx_func);
63099         h_proxy = NULL;  /* invalidated */
63100         DUK_ASSERT(duk_get_top(thr) == idx_func + 5);
63101 }
63102 #endif  /* DUK_USE_ES6_PROXY */
63103
63104 /*
63105  *  Helper for setting up var_env and lex_env of an activation,
63106  *  assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
63107  */
63108
63109 DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
63110                                            duk_hobject *func,
63111                                            duk_activation *act) {
63112         duk_hcompfunc *f;
63113         duk_hobject *h_lex;
63114         duk_hobject *h_var;
63115
63116         DUK_ASSERT(thr != NULL);
63117         DUK_ASSERT(func != NULL);
63118         DUK_ASSERT(act != NULL);
63119         DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func));
63120         DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
63121         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(func));
63122         DUK_UNREF(thr);
63123
63124         f = (duk_hcompfunc *) func;
63125         h_lex = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
63126         h_var = DUK_HCOMPFUNC_GET_VARENV(thr->heap, f);
63127         DUK_ASSERT(h_lex != NULL);  /* Always true for closures (not for templates) */
63128         DUK_ASSERT(h_var != NULL);
63129         act->lex_env = h_lex;
63130         act->var_env = h_var;
63131         DUK_HOBJECT_INCREF(thr, h_lex);
63132         DUK_HOBJECT_INCREF(thr, h_var);
63133 }
63134
63135 /*
63136  *  Helper for updating callee 'caller' property.
63137  */
63138
63139 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
63140 DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
63141         duk_tval *tv_caller;
63142         duk_hobject *h_tmp;
63143         duk_activation *act_callee;
63144         duk_activation *act_caller;
63145
63146         DUK_ASSERT(thr != NULL);
63147         DUK_ASSERT(func != NULL);
63148         DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));  /* bound chain resolved */
63149         DUK_ASSERT(thr->callstack_top >= 1);
63150
63151         if (DUK_HOBJECT_HAS_STRICT(func)) {
63152                 /* Strict functions don't get their 'caller' updated. */
63153                 return;
63154         }
63155
63156         DUK_ASSERT(thr->callstack_top > 0);
63157         act_callee = thr->callstack_curr;
63158         DUK_ASSERT(act_callee != NULL);
63159         act_caller = (thr->callstack_top >= 2 ? act_callee->parent : NULL);
63160
63161         /* XXX: check .caller writability? */
63162
63163         /* Backup 'caller' property and update its value. */
63164         tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
63165         if (tv_caller) {
63166                 /* If caller is global/eval code, 'caller' should be set to
63167                  * 'null'.
63168                  *
63169                  * XXX: there is no exotic flag to infer this correctly now.
63170                  * The NEWENV flag is used now which works as intended for
63171                  * everything (global code, non-strict eval code, and functions)
63172                  * except strict eval code.  Bound functions are never an issue
63173                  * because 'func' has been resolved to a non-bound function.
63174                  */
63175
63176                 if (act_caller != NULL) {
63177                         /* act_caller->func may be NULL in some finalization cases,
63178                          * just treat like we don't know the caller.
63179                          */
63180                         if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) {
63181                                 /* Setting to NULL causes 'caller' to be set to
63182                                  * 'null' as desired.
63183                                  */
63184                                 act_caller = NULL;
63185                         }
63186                 }
63187
63188                 if (DUK_TVAL_IS_OBJECT(tv_caller)) {
63189                         h_tmp = DUK_TVAL_GET_OBJECT(tv_caller);
63190                         DUK_ASSERT(h_tmp != NULL);
63191                         act_callee->prev_caller = h_tmp;
63192
63193                         /* Previous value doesn't need refcount changes because its ownership
63194                          * is transferred to prev_caller.
63195                          */
63196
63197                         if (act_caller != NULL) {
63198                                 DUK_ASSERT(act_caller->func != NULL);
63199                                 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
63200                                 DUK_TVAL_INCREF(thr, tv_caller);
63201                         } else {
63202                                 DUK_TVAL_SET_NULL(tv_caller);  /* no incref */
63203                         }
63204                 } else {
63205                         /* 'caller' must only take on 'null' or function value */
63206                         DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
63207                         DUK_ASSERT(act_callee->prev_caller == NULL);
63208                         if (act_caller != NULL && act_caller->func) {
63209                                 /* Tolerate act_caller->func == NULL which happens in
63210                                  * some finalization cases; treat like unknown caller.
63211                                  */
63212                                 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
63213                                 DUK_TVAL_INCREF(thr, tv_caller);
63214                         } else {
63215                                 DUK_TVAL_SET_NULL(tv_caller);  /* no incref */
63216                         }
63217                 }
63218         }
63219 }
63220 #endif  /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
63221
63222 /*
63223  *  Shared helpers for resolving the final, non-bound target function of the
63224  *  call and the effective 'this' binding.  Resolves bound functions and
63225  *  applies .call(), .apply(), and .construct() inline.
63226  *
63227  *  Proxy traps are also handled inline so that if the target is a Proxy with
63228  *  a 'call' or 'construct' trap, the trap handler is called with a modified
63229  *  argument list.
63230  *
63231  *  Once the bound function / .call() / .apply() / .construct() sequence has
63232  *  been resolved, the value at idx_func + 1 may need coercion described in
63233  *  E5 Section 10.4.3.
63234  *
63235  *  A call that begins as a non-constructor call may be converted into a
63236  *  constructor call during the resolution process if Reflect.construct()
63237  *  is invoked.  This is handled by updating the caller's call_flags.
63238  *
63239  *  For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
63240  *  that the caller has provided the correct 'this' binding explicitly
63241  *  when calling, i.e.:
63242  *
63243  *    - global code: this=global object
63244  *    - direct eval: this=copy from eval() caller's this binding
63245  *    - other eval:  this=global object
63246  *
63247  *  The 'this' coercion may cause a recursive function call with arbitrary
63248  *  side effects, because ToObject() may be called.
63249  */
63250
63251 DUK_LOCAL DUK_INLINE void duk__coerce_nonstrict_this_binding(duk_hthread *thr, duk_idx_t idx_this) {
63252         duk_tval *tv_this;
63253         duk_hobject *obj_global;
63254
63255         tv_this = thr->valstack_bottom + idx_this;
63256         switch (DUK_TVAL_GET_TAG(tv_this)) {
63257         case DUK_TAG_OBJECT:
63258                 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
63259                 break;
63260         case DUK_TAG_UNDEFINED:
63261         case DUK_TAG_NULL:
63262                 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object"));
63263                 obj_global = thr->builtins[DUK_BIDX_GLOBAL];
63264                 /* XXX: avoid this check somehow */
63265                 if (DUK_LIKELY(obj_global != NULL)) {
63266                         DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this));  /* no need to decref previous value */
63267                         DUK_TVAL_SET_OBJECT(tv_this, obj_global);
63268                         DUK_HOBJECT_INCREF(thr, obj_global);
63269                 } else {
63270                         /* This may only happen if built-ins are being "torn down".
63271                          * This behavior is out of specification scope.
63272                          */
63273                         DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead"));
63274                         DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this));  /* no need to decref previous value */
63275                         DUK_TVAL_SET_UNDEFINED(tv_this);  /* nothing to incref */
63276                 }
63277                 break;
63278         default:
63279                 /* Plain buffers and lightfuncs are object coerced.  Lightfuncs
63280                  * very rarely come here however, because the call target would
63281                  * need to be a non-strict non-lightfunc (lightfuncs are considered
63282                  * strict) with an explicit lightfunc 'this' binding.
63283                  */
63284                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
63285                 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
63286                 duk_to_object(thr, idx_this);  /* may have side effects */
63287                 break;
63288         }
63289 }
63290
63291 DUK_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) {
63292 #if defined(DUK_USE_PREFER_SIZE)
63293         DUK_UNREF(thr);
63294         DUK_UNREF(idx_func);
63295         DUK_UNREF(out_func);
63296         DUK_UNREF(call_flags);
63297 #else  /* DUK_USE_PREFER_SIZE */
63298         duk_tval *tv_func;
63299         duk_hobject *func;
63300
63301         if (DUK_UNLIKELY(call_flags & DUK_CALL_FLAG_CONSTRUCT)) {
63302                 return 0;
63303         }
63304
63305         tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
63306         DUK_ASSERT(tv_func != NULL);
63307
63308         if (DUK_LIKELY(DUK_TVAL_IS_OBJECT(tv_func))) {
63309                 func = DUK_TVAL_GET_OBJECT(tv_func);
63310                 if (DUK_HOBJECT_IS_CALLABLE(func) &&
63311                     !DUK_HOBJECT_HAS_BOUNDFUNC(func) &&
63312                     !DUK_HOBJECT_HAS_SPECIAL_CALL(func)) {
63313                         *out_func = func;
63314
63315                         if (DUK_HOBJECT_HAS_STRICT(func)) {
63316                                 /* Strict function: no 'this' coercion. */
63317                                 return 1;
63318                         }
63319
63320                         duk__coerce_nonstrict_this_binding(thr, idx_func + 1);
63321                         return 1;
63322                 }
63323         } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
63324                 *out_func = NULL;
63325
63326                 /* Lightfuncs are considered strict, so 'this' binding is
63327                  * used as is.  They're never bound, always constructable,
63328                  * and never special functions.
63329                  */
63330                 return 1;
63331         }
63332 #endif  /* DUK_USE_PREFER_SIZE */
63333         return 0;  /* let slow path deal with it */
63334 }
63335
63336 DUK_LOCAL duk_hobject *duk__resolve_target_func_and_this_binding(duk_hthread *thr,
63337                                                                  duk_idx_t idx_func,
63338                                                                  duk_small_uint_t *call_flags) {
63339         duk_tval *tv_func;
63340         duk_hobject *func;
63341         duk_bool_t first;
63342
63343         DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
63344
63345         for (first = 1;; first = 0) {
63346                 DUK_ASSERT(duk_get_top(thr) >= idx_func + 2);
63347
63348                 tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
63349                 DUK_ASSERT(tv_func != NULL);
63350
63351                 if (DUK_TVAL_IS_OBJECT(tv_func)) {
63352                         func = DUK_TVAL_GET_OBJECT(tv_func);
63353
63354                         if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
63355                                 if (DUK_UNLIKELY(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func))) {
63356                                         goto not_constructable;
63357                                 }
63358                         } else {
63359                                 if (DUK_UNLIKELY(!DUK_HOBJECT_IS_CALLABLE(func))) {
63360                                         goto not_callable;
63361                                 }
63362                         }
63363
63364                         if (DUK_LIKELY(!DUK_HOBJECT_HAS_BOUNDFUNC(func) &&
63365                                        !DUK_HOBJECT_HAS_SPECIAL_CALL(func) &&
63366                                        !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func))) {
63367                                 /* Common case, so test for using a single bitfield test.
63368                                  * Break out to handle this coercion etc.
63369                                  */
63370                                 break;
63371                         }
63372
63373                         /* XXX: could set specialcall for boundfuncs too, simplify check above */
63374
63375                         if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
63376                                 DUK_ASSERT(!DUK_HOBJECT_HAS_SPECIAL_CALL(func));
63377                                 DUK_ASSERT(!DUK_HOBJECT_IS_NATFUNC(func));
63378
63379                                 /* Callable/constructable flags are the same
63380                                  * for the bound function and its target, so
63381                                  * we don't need to check them here, we can
63382                                  * check them from the target only.
63383                                  */
63384                                 duk__handle_bound_chain_for_call(thr, idx_func, *call_flags & DUK_CALL_FLAG_CONSTRUCT);
63385
63386                                 DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(thr, idx_func)) ||
63387                                            DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(thr, idx_func)));
63388                         } else {
63389                                 DUK_ASSERT(DUK_HOBJECT_HAS_SPECIAL_CALL(func));
63390
63391 #if defined(DUK_USE_ES6_PROXY)
63392                                 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(func)) {
63393                                         /* If no trap, resume processing from Proxy trap.
63394                                          * If trap exists, helper converts call into a trap
63395                                          * call; this may change a constructor call into a
63396                                          * normal (non-constructor) trap call.  We must
63397                                          * continue processing even when a trap is found as
63398                                          * the trap may be bound.
63399                                          */
63400                                         duk__handle_proxy_for_call(thr, idx_func, (duk_hproxy *) func, call_flags);
63401                                 }
63402                                 else
63403 #endif
63404                                 {
63405                                         DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
63406                                         DUK_ASSERT(DUK_HOBJECT_HAS_CALLABLE(func));
63407                                         DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE(func));
63408                                         /* Constructable check already done above. */
63409
63410                                         if (duk__handle_specialfuncs_for_call(thr, idx_func, func, call_flags, first) != 0) {
63411                                                 /* Encountered native eval call, normal call
63412                                                  * context.  Break out, handle this coercion etc.
63413                                                  */
63414                                                 break;
63415                                         }
63416                                 }
63417                         }
63418                         /* Retry loop. */
63419                 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
63420                         /* Lightfuncs are:
63421                          *   - Always strict, so no 'this' coercion.
63422                          *   - Always callable.
63423                          *   - Always constructable.
63424                          *   - Never specialfuncs.
63425                          */
63426                         func = NULL;
63427                         goto finished;
63428                 } else {
63429                         goto not_callable;
63430                 }
63431         }
63432
63433         DUK_ASSERT(func != NULL);
63434
63435         if (!DUK_HOBJECT_HAS_STRICT(func)) {
63436                 /* Non-strict target needs 'this' coercion.
63437                  * This has potential side effects invalidating
63438                  * 'tv_func'.
63439                  */
63440                 duk__coerce_nonstrict_this_binding(thr, idx_func + 1);
63441         }
63442         if (*call_flags & DUK_CALL_FLAG_CONSTRUCT) {
63443                 if (!(*call_flags & DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED)) {
63444                         *call_flags |= DUK_CALL_FLAG_DEFAULT_INSTANCE_UPDATED;
63445                         duk__update_default_instance_proto(thr, idx_func);
63446                 }
63447         }
63448
63449  finished:
63450
63451 #if defined(DUK_USE_ASSERTIONS)
63452         {
63453                 duk_tval *tv_tmp;
63454
63455                 tv_tmp = duk_get_tval(thr, idx_func);
63456                 DUK_ASSERT(tv_tmp != NULL);
63457
63458                 DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_tmp) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_tmp))) ||
63459                            DUK_TVAL_IS_LIGHTFUNC(tv_tmp));
63460                 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
63461                 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
63462                                             DUK_HOBJECT_IS_NATFUNC(func)));
63463                 DUK_ASSERT(func == NULL || (DUK_HOBJECT_HAS_CONSTRUCTABLE(func) ||
63464                                             (*call_flags & DUK_CALL_FLAG_CONSTRUCT) == 0));
63465         }
63466 #endif
63467
63468         return func;
63469
63470  not_callable:
63471         DUK_ASSERT(tv_func != NULL);
63472
63473 #if defined(DUK_USE_VERBOSE_ERRORS)
63474         /* GETPROPC delayed error handling: when target is not callable,
63475          * GETPROPC replaces idx_func+0 with an Error (non-callable) with
63476          * a hidden Symbol to signify it's to be thrown as is here.  The
63477          * hidden Symbol is only checked as an own property, not inherited
63478          * (which would be dangerous).
63479          */
63480         if (DUK_TVAL_IS_OBJECT(tv_func)) {
63481                 if (duk_hobject_find_existing_entry_tval_ptr(thr->heap, DUK_TVAL_GET_OBJECT(tv_func), DUK_HTHREAD_STRING_INT_TARGET(thr)) != NULL) {
63482                         duk_push_tval(thr, tv_func);
63483                         (void) duk_throw(thr);
63484                         DUK_WO_NORETURN(return NULL;);
63485                 }
63486         }
63487 #endif
63488
63489 #if defined(DUK_USE_VERBOSE_ERRORS)
63490 #if defined(DUK_USE_PARANOID_ERRORS)
63491         DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_get_type_name(thr, idx_func));
63492 #else
63493         DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(thr, tv_func));
63494 #endif
63495 #else
63496         DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
63497 #endif
63498         DUK_WO_NORETURN(return NULL;);
63499
63500  not_constructable:
63501         /* For now GETPROPC delayed error not needed for constructor calls. */
63502 #if defined(DUK_USE_VERBOSE_ERRORS)
63503 #if defined(DUK_USE_PARANOID_ERRORS)
63504         DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(thr, idx_func));
63505 #else
63506         DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_tval_readable(thr, tv_func));
63507 #endif
63508 #else
63509         DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
63510 #endif
63511         DUK_WO_NORETURN(return NULL;);
63512 }
63513
63514 /*
63515  *  Manipulate value stack so that exactly 'num_stack_rets' return
63516  *  values are at 'idx_retbase' in every case, assuming there are
63517  *  'rc' return values on top of stack.
63518  *
63519  *  This is a bit tricky, because the called C function operates in
63520  *  the same activation record and may have e.g. popped the stack
63521  *  empty (below idx_retbase).
63522  */
63523
63524 DUK_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) {
63525         duk_idx_t idx_rcbase;
63526
63527         DUK_ASSERT(thr != NULL);
63528         DUK_ASSERT(idx_retbase >= 0);
63529         DUK_ASSERT(num_stack_rets >= 0);
63530         DUK_ASSERT(num_actual_rets >= 0);
63531
63532         idx_rcbase = duk_get_top(thr) - num_actual_rets;  /* base of known return values */
63533         if (DUK_UNLIKELY(idx_rcbase < 0)) {
63534                 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
63535                 DUK_WO_NORETURN(return;);
63536         }
63537
63538         DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
63539                              "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
63540                              (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(thr),
63541                              (long) idx_retbase, (long) idx_rcbase));
63542
63543         DUK_ASSERT(idx_rcbase >= 0);  /* caller must check */
63544
63545         /* Space for num_stack_rets was reserved before the safe call.
63546          * Because value stack reserve cannot shrink except in call returns,
63547          * the reserve is still in place.  Adjust valstack, carefully
63548          * ensuring we don't overstep the reserve.
63549          */
63550
63551         /* Match idx_rcbase with idx_retbase so that the return values
63552          * start at the correct index.
63553          */
63554         if (idx_rcbase > idx_retbase) {
63555                 duk_idx_t count = idx_rcbase - idx_retbase;
63556
63557                 DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
63558                                      "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
63559
63560                 /* Remove values between irc_rcbase (start of intended return
63561                  * values) and idx_retbase to lower return values to idx_retbase.
63562                  */
63563                 DUK_ASSERT(count > 0);
63564                 duk_remove_n(thr, idx_retbase, count);  /* may be NORZ */
63565         } else {
63566                 duk_idx_t count = idx_retbase - idx_rcbase;
63567
63568                 DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
63569                                      "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
63570
63571                 /* Insert 'undefined' at idx_rcbase (start of intended return
63572                  * values) to lift return values to idx_retbase.
63573                  */
63574                 DUK_ASSERT(count >= 0);
63575                 DUK_ASSERT(thr->valstack_end - thr->valstack_top >= count);  /* reserve cannot shrink */
63576                 duk_insert_undefined_n(thr, idx_rcbase, count);
63577         }
63578
63579         /* Chop extra retvals away / extend with undefined. */
63580         duk_set_top_unsafe(thr, idx_retbase + num_stack_rets);
63581 }
63582
63583 /*
63584  *  Activation setup for tailcalls and non-tailcalls.
63585  */
63586
63587 #if defined(DUK_USE_TAILCALL)
63588 DUK_LOCAL duk_small_uint_t duk__call_setup_act_attempt_tailcall(duk_hthread *thr,
63589                                                                 duk_small_uint_t call_flags,
63590                                                                 duk_idx_t idx_func,
63591                                                                 duk_hobject *func,
63592                                                                 duk_size_t entry_valstack_bottom_byteoff,
63593                                                                 duk_size_t entry_valstack_end_byteoff,
63594                                                                 duk_idx_t *out_nargs,
63595                                                                 duk_idx_t *out_nregs,
63596                                                                 duk_size_t *out_vs_min_bytes,
63597                                                                 duk_activation **out_act) {
63598         duk_activation *act;
63599         duk_tval *tv1, *tv2;
63600         duk_idx_t idx_args;
63601         duk_small_uint_t flags1, flags2;
63602 #if defined(DUK_USE_DEBUGGER_SUPPORT)
63603         duk_activation *prev_pause_act;
63604 #endif
63605
63606         DUK_UNREF(entry_valstack_end_byteoff);
63607
63608         /* Tailcall cannot be flagged to resume calls, and a
63609          * previous frame must exist.
63610          */
63611         DUK_ASSERT(thr->callstack_top >= 1);
63612
63613         act = thr->callstack_curr;
63614         DUK_ASSERT(act != NULL);
63615         *out_act = act;
63616
63617         if (func == NULL || !DUK_HOBJECT_IS_COMPFUNC(func)) {
63618                 DUK_DDD(DUK_DDDPRINT("tail call prevented by target not being ecma function"));
63619                 return 0;
63620         }
63621         if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
63622                 DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENT_YIELD"));
63623                 return 0;
63624         }
63625         /* Tailcall is only allowed if current and candidate
63626          * function have identical return value handling.  There
63627          * are three possible return value handling cases:
63628          *   1. Normal function call, no special return value handling.
63629          *   2. Constructor call, return value replacement object check.
63630          *   3. Proxy 'construct' trap call, return value invariant check.
63631          */
63632         flags1 = (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT) ? 1 : 0)
63633 #if defined(DUK_USE_ES6_PROXY)
63634                  | (duk_small_uint_t) ((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) ? 2 : 0)
63635 #endif
63636                  ;
63637         flags2 = (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) ? 1 : 0)
63638 #if defined(DUK_USE_ES6_PROXY)
63639                  | (duk_small_uint_t) ((call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) ? 2 : 0);
63640 #endif
63641                  ;
63642         if (flags1 != flags2) {
63643                 DUK_DDD(DUK_DDDPRINT("tail call prevented by incompatible return value handling"));
63644                 return 0;
63645         }
63646         DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT) && (call_flags & DUK_CALL_FLAG_CONSTRUCT)) ||
63647                    (!(act->flags & DUK_ACT_FLAG_CONSTRUCT) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT)));
63648         DUK_ASSERT(((act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)) ||
63649                    (!(act->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY) && !(call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY)));
63650         if (DUK_HOBJECT_HAS_NOTAIL(func)) {
63651                 /* See: test-bug-tailcall-preventyield-assert.c. */
63652                 DUK_DDD(DUK_DDDPRINT("tail call prevented by function having a notail flag"));
63653                 return 0;
63654         }
63655
63656         /*
63657          *  Tailcall handling
63658          *
63659          *  Although the callstack entry is reused, we need to explicitly unwind
63660          *  the current activation (or simulate an unwind).  In particular, the
63661          *  current activation must be closed, otherwise something like
63662          *  test-bug-reduce-judofyr.js results.  Also catchers need to be unwound
63663          *  because there may be non-error-catching label entries in valid tail calls.
63664          *
63665          *  Special attention is needed for debugger and pause behavior when
63666          *  reusing an activation.
63667          *    - Disable StepOut processing for the activation unwind because
63668          *      we reuse the activation, see:
63669          *      https://github.com/svaarala/duktape/issues/1684.
63670          *    - Disable line change pause flag permanently if act == dbg_pause_act
63671          *      (if set) because it would no longer be relevant, see:
63672          *      https://github.com/svaarala/duktape/issues/1726,
63673          *      https://github.com/svaarala/duktape/issues/1786.
63674          *    - Check for function entry (e.g. StepInto) pause flag here, because
63675          *      the executor pause check won't trigger due to shared activation, see:
63676          *      https://github.com/svaarala/duktape/issues/1726.
63677          */
63678
63679         DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
63680                              (long) (thr->callstack_top - 1)));
63681
63682         DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
63683         DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func));
63684         DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
63685         DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
63686         DUK_ASSERT(call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA);
63687
63688         /* Unwind the topmost callstack entry before reusing it.  This
63689          * also unwinds the catchers related to the topmost entry.
63690          */
63691         DUK_ASSERT(thr->callstack_top > 0);
63692         DUK_ASSERT(thr->callstack_curr != NULL);
63693 #if defined(DUK_USE_DEBUGGER_SUPPORT)
63694         if (act == thr->heap->dbg_pause_act) {
63695                 thr->heap->dbg_pause_flags &= ~DUK_PAUSE_FLAG_LINE_CHANGE;
63696         }
63697
63698         prev_pause_act = thr->heap->dbg_pause_act;
63699         thr->heap->dbg_pause_act = NULL;
63700         if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) {
63701                 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry (tailcall)"));
63702                 duk_debug_set_paused(thr->heap);
63703         }
63704 #endif
63705         duk_hthread_activation_unwind_reuse_norz(thr);
63706 #if defined(DUK_USE_DEBUGGER_SUPPORT)
63707         thr->heap->dbg_pause_act = prev_pause_act;
63708 #endif
63709         DUK_ASSERT(act == thr->callstack_curr);
63710
63711         /* XXX: We could restore the caller's value stack reserve
63712          * here, as if we did an actual unwind-and-call.  Without
63713          * the restoration, value stack reserve may remain higher
63714          * than would otherwise be possible until we return to a
63715          * non-tailcall.
63716          */
63717
63718         /* Then reuse the unwound activation. */
63719         act->cat = NULL;
63720         act->var_env = NULL;
63721         act->lex_env = NULL;
63722         DUK_ASSERT(func != NULL);
63723         DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
63724         act->func = func;  /* don't want an intermediate exposed state with func == NULL */
63725 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
63726         act->prev_caller = NULL;
63727 #endif
63728         /* don't want an intermediate exposed state with invalid pc */
63729         act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
63730 #if defined(DUK_USE_DEBUGGER_SUPPORT)
63731         act->prev_line = 0;
63732 #endif
63733         DUK_TVAL_SET_OBJECT(&act->tv_func, func);  /* borrowed, no refcount */
63734         DUK_HOBJECT_INCREF(thr, func);
63735
63736         act->flags = DUK_ACT_FLAG_TAILCALLED;
63737         if (DUK_HOBJECT_HAS_STRICT(func)) {
63738                 act->flags |= DUK_ACT_FLAG_STRICT;
63739         }
63740         if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
63741                 act->flags |= DUK_ACT_FLAG_CONSTRUCT;
63742         }
63743 #if defined(DUK_USE_ES6_PROXY)
63744         if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) {
63745                 act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY;
63746         }
63747 #endif
63748
63749         DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func);      /* already updated */
63750         DUK_ASSERT(act->var_env == NULL);
63751         DUK_ASSERT(act->lex_env == NULL);
63752         act->bottom_byteoff = entry_valstack_bottom_byteoff;  /* tail call -> reuse current "frame" */
63753 #if 0
63754         /* Topmost activation retval_byteoff is considered garbage, no need to init. */
63755         act->retval_byteoff = 0;
63756 #endif
63757         /* Filled in when final reserve is known, dummy value doesn't matter
63758          * even in error unwind because reserve_byteoff is only used when
63759          * returning to -this- activation.
63760          */
63761         act->reserve_byteoff = 0;
63762
63763         /*
63764          *  Manipulate valstack so that args are on the current bottom and the
63765          *  previous caller's 'this' binding (which is the value preceding the
63766          *  current bottom) is replaced with the new 'this' binding:
63767          *
63768          *       [ ... this_old | (crud) func this_new arg1 ... argN ]
63769          *  -->  [ ... this_new | arg1 ... argN ]
63770          *
63771          *  For tail calling to work properly, the valstack bottom must not grow
63772          *  here; otherwise crud would accumulate on the valstack.
63773          */
63774
63775         tv1 = thr->valstack_bottom - 1;
63776         tv2 = thr->valstack_bottom + idx_func + 1;
63777         DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);  /* tv1 is -below- valstack_bottom */
63778         DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
63779         DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2);  /* side effects */
63780
63781         idx_args = idx_func + 2;
63782         duk_remove_n(thr, 0, idx_args);  /* may be NORZ */
63783
63784         idx_func = 0; DUK_UNREF(idx_func);  /* really 'not applicable' anymore, should not be referenced after this */
63785         idx_args = 0;
63786
63787         *out_nargs = ((duk_hcompfunc *) func)->nargs;
63788         *out_nregs = ((duk_hcompfunc *) func)->nregs;
63789         DUK_ASSERT(*out_nregs >= 0);
63790         DUK_ASSERT(*out_nregs >= *out_nargs);
63791         *out_vs_min_bytes = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA);
63792
63793
63794 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
63795 #if defined(DUK_USE_TAILCALL)
63796 #error incorrect options: tail calls enabled with function caller property
63797 #endif
63798         /* XXX: This doesn't actually work properly for tail calls, so
63799          * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
63800          * is in use.
63801          */
63802         duk__update_func_caller_prop(thr, func);
63803 #endif
63804
63805         /* [ ... this_new | arg1 ... argN ] */
63806
63807         return 1;
63808 }
63809 #endif  /* DUK_USE_TAILCALL */
63810
63811 DUK_LOCAL void duk__call_setup_act_not_tailcall(duk_hthread *thr,
63812                                                 duk_small_uint_t call_flags,
63813                                                 duk_idx_t idx_func,
63814                                                 duk_hobject *func,
63815                                                 duk_size_t entry_valstack_bottom_byteoff,
63816                                                 duk_size_t entry_valstack_end_byteoff,
63817                                                 duk_idx_t *out_nargs,
63818                                                 duk_idx_t *out_nregs,
63819                                                 duk_size_t *out_vs_min_bytes,
63820                                                 duk_activation **out_act) {
63821         duk_activation *act;
63822         duk_activation *new_act;
63823
63824         DUK_UNREF(entry_valstack_end_byteoff);
63825
63826         DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
63827                              (long) (thr->callstack_top)));
63828
63829         duk__call_callstack_limit_check(thr);
63830         new_act = duk_hthread_activation_alloc(thr);
63831         DUK_ASSERT(new_act != NULL);
63832
63833         act = thr->callstack_curr;
63834         if (act != NULL) {
63835                 /*
63836                  *  Update return value stack index of current activation (if any).
63837                  *
63838                  *  Although it might seem this is not necessary (bytecode executor
63839                  *  does this for ECMAScript-to-ECMAScript calls; other calls are
63840                  *  handled here), this turns out to be necessary for handling yield
63841                  *  and resume.  For them, an ECMAScript-to-native call happens, and
63842                  *  the ECMAScript call's retval_byteoff must be set for things to work.
63843                  */
63844
63845                 act->retval_byteoff = entry_valstack_bottom_byteoff + (duk_size_t) idx_func * sizeof(duk_tval);
63846         }
63847
63848         new_act->parent = act;
63849         thr->callstack_curr = new_act;
63850         thr->callstack_top++;
63851         act = new_act;
63852         *out_act = act;
63853
63854         DUK_ASSERT(thr->valstack_top > thr->valstack_bottom);  /* at least effective 'this' */
63855         DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
63856
63857         act->cat = NULL;
63858
63859         act->flags = 0;
63860         if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
63861                 act->flags |= DUK_ACT_FLAG_CONSTRUCT;
63862         }
63863 #if defined(DUK_USE_ES6_PROXY)
63864         if (call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY) {
63865                 act->flags |= DUK_ACT_FLAG_CONSTRUCT_PROXY;
63866         }
63867 #endif
63868         if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
63869                 act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
63870         }
63871
63872         /* start of arguments: idx_func + 2. */
63873         act->func = func;  /* NULL for lightfunc */
63874         if (DUK_LIKELY(func != NULL)) {
63875                 DUK_TVAL_SET_OBJECT(&act->tv_func, func);  /* borrowed, no refcount */
63876                 if (DUK_HOBJECT_HAS_STRICT(func)) {
63877                         act->flags |= DUK_ACT_FLAG_STRICT;
63878                 }
63879                 if (DUK_HOBJECT_IS_COMPFUNC(func)) {
63880                         *out_nargs = ((duk_hcompfunc *) func)->nargs;
63881                         *out_nregs = ((duk_hcompfunc *) func)->nregs;
63882                         DUK_ASSERT(*out_nregs >= 0);
63883                         DUK_ASSERT(*out_nregs >= *out_nargs);
63884                         *out_vs_min_bytes = entry_valstack_bottom_byteoff +
63885                                 sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_INTERNAL_EXTRA);
63886                 } else {
63887                         /* True because of call target lookup checks. */
63888                         DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
63889
63890                         *out_nargs = ((duk_hnatfunc *) func)->nargs;
63891                         *out_nregs = *out_nargs;
63892                         if (*out_nargs >= 0) {
63893                                 *out_vs_min_bytes = entry_valstack_bottom_byteoff +
63894                                         sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nregs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
63895                         } else {
63896                                 /* Vararg function. */
63897                                 duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack));
63898                                 *out_vs_min_bytes = valstack_top_byteoff +
63899                                         sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
63900                         }
63901                 }
63902         } else {
63903                 duk_small_uint_t lf_flags;
63904                 duk_tval *tv_func;
63905
63906                 act->flags |= DUK_ACT_FLAG_STRICT;
63907
63908                 tv_func = DUK_GET_TVAL_POSIDX(thr, idx_func);
63909                 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
63910                 DUK_TVAL_SET_TVAL(&act->tv_func, tv_func);  /* borrowed, no refcount */
63911
63912                 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
63913                 *out_nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
63914                 if (*out_nargs != DUK_LFUNC_NARGS_VARARGS) {
63915                         *out_vs_min_bytes = entry_valstack_bottom_byteoff +
63916                                 sizeof(duk_tval) * ((duk_size_t) idx_func + 2U + (duk_size_t) *out_nargs + DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
63917                 } else {
63918                         duk_size_t valstack_top_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - ((duk_uint8_t *) thr->valstack));
63919                         *out_vs_min_bytes = valstack_top_byteoff +
63920                                 sizeof(duk_tval) * (DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
63921                         *out_nargs = -1;  /* vararg */
63922                 }
63923                 *out_nregs = *out_nargs;
63924         }
63925
63926         act->var_env = NULL;
63927         act->lex_env = NULL;
63928 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
63929         act->prev_caller = NULL;
63930 #endif
63931         act->curr_pc = NULL;
63932 #if defined(DUK_USE_DEBUGGER_SUPPORT)
63933         act->prev_line = 0;
63934 #endif
63935         act->bottom_byteoff = entry_valstack_bottom_byteoff + sizeof(duk_tval) * ((duk_size_t) idx_func + 2U);
63936 #if 0
63937         act->retval_byteoff = 0;   /* topmost activation retval_byteoff is considered garbage, no need to init */
63938 #endif
63939         /* Filled in when final reserve is known, dummy value doesn't matter
63940          * even in error unwind because reserve_byteoff is only used when
63941          * returning to -this- activation.
63942          */
63943         act->reserve_byteoff = 0;  /* filled in by caller */
63944
63945         /* XXX: Is this INCREF necessary? 'func' is always a borrowed
63946          * reference reachable through the value stack?  If changed, stack
63947          * unwind code also needs to be fixed to match.
63948          */
63949         DUK_HOBJECT_INCREF_ALLOWNULL(thr, func);  /* act->func */
63950
63951 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
63952         if (func) {
63953                 duk__update_func_caller_prop(thr, func);
63954         }
63955 #endif
63956 }
63957
63958 /*
63959  *  Environment setup.
63960  */
63961
63962 DUK_LOCAL void duk__call_env_setup(duk_hthread *thr, duk_hobject *func, duk_activation *act, duk_idx_t idx_args) {
63963         duk_hobject *env;
63964
63965         DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));  /* bound function has already been resolved */
63966
63967         if (DUK_LIKELY(func != NULL)) {
63968                 if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
63969                         if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) {
63970                                 /* Use a new environment but there's no 'arguments' object;
63971                                  * delayed environment initialization.  This is the most
63972                                  * common case.
63973                                  */
63974                                 DUK_ASSERT(act->lex_env == NULL);
63975                                 DUK_ASSERT(act->var_env == NULL);
63976                         } else {
63977                                 /* Use a new environment and there's an 'arguments' object.
63978                                  * We need to initialize it right now.
63979                                  */
63980
63981                                 /* third arg: absolute index (to entire valstack) of bottom_byteoff of new activation */
63982                                 env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff);
63983                                 DUK_ASSERT(env != NULL);
63984
63985                                 /* [ ... func this arg1 ... argN envobj ] */
63986
63987                                 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
63988                                 duk__handle_createargs_for_call(thr, func, env, idx_args);
63989
63990                                 /* [ ... func this arg1 ... argN envobj ] */
63991
63992                                 act->lex_env = env;
63993                                 act->var_env = env;
63994                                 DUK_HOBJECT_INCREF(thr, env);
63995                                 DUK_HOBJECT_INCREF(thr, env);  /* XXX: incref by count (2) directly */
63996                                 duk_pop(thr);
63997                         }
63998                 } else {
63999                         /* Use existing env (e.g. for non-strict eval); cannot have
64000                          * an own 'arguments' object (but can refer to an existing one).
64001                          */
64002
64003                         DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
64004
64005                         duk__handle_oldenv_for_call(thr, func, act);
64006
64007                         DUK_ASSERT(act->lex_env != NULL);
64008                         DUK_ASSERT(act->var_env != NULL);
64009                 }
64010         } else {
64011                 /* Lightfuncs are always native functions and have "newenv". */
64012                 DUK_ASSERT(act->lex_env == NULL);
64013                 DUK_ASSERT(act->var_env == NULL);
64014         }
64015 }
64016
64017 /*
64018  *  Misc shared helpers.
64019  */
64020
64021 /* Check thread state, update current thread. */
64022 DUK_LOCAL void duk__call_thread_state_update(duk_hthread *thr) {
64023         DUK_ASSERT(thr != NULL);
64024
64025         if (DUK_LIKELY(thr == thr->heap->curr_thread)) {
64026                 if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_RUNNING)) {
64027                         /* Should actually never happen, but check anyway. */
64028                         goto thread_state_error;
64029                 }
64030         } else {
64031                 DUK_ASSERT(thr->heap->curr_thread == NULL ||
64032                            thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
64033                 if (DUK_UNLIKELY(thr->state != DUK_HTHREAD_STATE_INACTIVE)) {
64034                         goto thread_state_error;
64035                 }
64036                 DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
64037                 thr->state = DUK_HTHREAD_STATE_RUNNING;
64038
64039                 /* Multiple threads may be simultaneously in the RUNNING
64040                  * state, but not in the same "resume chain".
64041                  */
64042         }
64043         DUK_ASSERT(thr->heap->curr_thread == thr);
64044         DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
64045         return;
64046
64047  thread_state_error:
64048         DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state (%ld)", (long) thr->state);
64049         DUK_WO_NORETURN(return;);
64050 }
64051
64052 /*
64053  *  Main unprotected call handler, handles:
64054  *
64055  *    - All combinations of native/ECMAScript caller and native/ECMAScript
64056  *      target.
64057  *
64058  *    - Optimized ECMAScript-to-ECMAScript call where call handling only
64059  *      sets up a new duk_activation but reuses an existing bytecode executor
64060  *      (the caller) without native recursion.
64061  *
64062  *    - Tailcalls, where an activation is reused without increasing call
64063  *      stack (duk_activation) depth.
64064  *
64065  *    - Setup for an initial Duktape.Thread.resume().
64066  *
64067  *  The call handler doesn't provide any protection guarantees, protected calls
64068  *  must be implemented e.g. by wrapping the call in a duk_safe_call().
64069  *  Call setup may fail at any stage, even when the new activation is in
64070  *  place; the only guarantee is that the state is consistent for unwinding.
64071  */
64072
64073 DUK_LOCAL duk_int_t duk__handle_call_raw(duk_hthread *thr,
64074                                          duk_idx_t idx_func,
64075                                          duk_small_uint_t call_flags) {
64076 #if defined(DUK_USE_ASSERTIONS)
64077         duk_activation *entry_act;
64078         duk_size_t entry_callstack_top;
64079 #endif
64080         duk_size_t entry_valstack_bottom_byteoff;
64081         duk_size_t entry_valstack_end_byteoff;
64082         duk_int_t entry_call_recursion_depth;
64083         duk_hthread *entry_curr_thread;
64084         duk_uint_fast8_t entry_thread_state;
64085         duk_instr_t **entry_ptr_curr_pc;
64086         duk_idx_t idx_args;
64087         duk_idx_t nargs;            /* # argument registers target function wants (< 0 => "as is") */
64088         duk_idx_t nregs;            /* # total registers target function wants on entry (< 0 => "as is") */
64089         duk_size_t vs_min_bytes;    /* minimum value stack size (bytes) for handling call */
64090         duk_hobject *func;          /* 'func' on stack (borrowed reference) */
64091         duk_activation *act;
64092         duk_ret_t rc;
64093         duk_small_uint_t use_tailcall;
64094
64095         DUK_ASSERT(thr != NULL);
64096         DUK_ASSERT(thr->heap != NULL);
64097         /* Asserts for heap->curr_thread omitted: it may be NULL, 'thr', or
64098          * any other thread (e.g. when heap thread is used to run finalizers).
64099          */
64100         DUK_ASSERT_CTX_VALID(thr);
64101         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
64102         DUK_ASSERT(idx_func >= 0);
64103
64104         DUK_STATS_INC(thr->heap, stats_call_all);
64105
64106         /* If a tail call:
64107          *   - an ECMAScript activation must be on top of the callstack
64108          *   - there cannot be any catch stack entries that would catch
64109          *     a return
64110          */
64111 #if defined(DUK_USE_ASSERTIONS)
64112         if (call_flags & DUK_CALL_FLAG_TAILCALL) {
64113                 duk_activation *tmp_act;
64114                 duk_catcher *tmp_cat;
64115
64116                 DUK_ASSERT(thr->callstack_top >= 1);
64117                 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
64118                 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
64119
64120                 /* No entry in the catch stack which would actually catch a
64121                  * throw can refer to the callstack entry being reused.
64122                  * There *can* be catch stack entries referring to the current
64123                  * callstack entry as long as they don't catch (e.g. label sites).
64124                  */
64125
64126                 tmp_act = thr->callstack_curr;
64127                 for (tmp_cat = tmp_act->cat; tmp_cat != NULL; tmp_cat = tmp_cat->parent) {
64128                         DUK_ASSERT(DUK_CAT_GET_TYPE(tmp_cat) == DUK_CAT_TYPE_LABEL); /* a non-catching entry */
64129                 }
64130         }
64131 #endif  /* DUK_USE_ASSERTIONS */
64132
64133         /*
64134          *  Store entry state.
64135          */
64136
64137 #if defined(DUK_USE_ASSERTIONS)
64138         entry_act = thr->callstack_curr;
64139         entry_callstack_top = thr->callstack_top;
64140 #endif
64141         entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
64142         entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
64143         entry_call_recursion_depth = thr->heap->call_recursion_depth;
64144         entry_curr_thread = thr->heap->curr_thread;  /* may be NULL if first call */
64145         entry_thread_state = thr->state;
64146         entry_ptr_curr_pc = thr->ptr_curr_pc;  /* may be NULL */
64147
64148         /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc.  Then NULL
64149          * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
64150          * activation when side effects occur.
64151          */
64152         duk_hthread_sync_and_null_currpc(thr);
64153         DUK_ASSERT(thr->ptr_curr_pc == NULL);
64154
64155         DUK_DD(DUK_DDPRINT("duk__handle_call_raw: thr=%p, idx_func=%ld, "
64156                            "call_flags=0x%08lx (constructor=%ld), "
64157                            "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
64158                            "entry_valstack_bottom_byteoff=%ld, entry_valstack_end_byteoff=%ld, "
64159                            "entry_call_recursion_depth=%ld, "
64160                            "entry_curr_thread=%p, entry_thread_state=%ld",
64161                            (void *) thr,
64162                            (long) idx_func,
64163                            (unsigned long) call_flags,
64164                            (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCT) != 0 ? 1 : 0),
64165                            (long) duk_get_top(thr),
64166                            (long) idx_func,
64167                            (long) (idx_func + 2),
64168                            (long) thr->heap->call_recursion_depth,
64169                            (long) thr->heap->call_recursion_limit,
64170                            (long) entry_valstack_bottom_byteoff,
64171                            (long) entry_valstack_end_byteoff,
64172                            (long) entry_call_recursion_depth,
64173                            (void *) entry_curr_thread,
64174                            (long) entry_thread_state));
64175
64176         /*
64177          *  Thread state check and book-keeping.
64178          */
64179
64180         duk__call_thread_state_update(thr);
64181
64182         /*
64183          *  Resolve final target function; handle bound functions and special
64184          *  functions like .call() and .apply().  Also figure out the effective
64185          *  'this' binding, which replaces the current value at idx_func + 1.
64186          */
64187
64188         if (DUK_LIKELY(duk__resolve_target_fastpath_check(thr, idx_func, &func, call_flags) != 0U)) {
64189                 DUK_DDD(DUK_DDDPRINT("fast path target resolve"));
64190         } else {
64191                 DUK_DDD(DUK_DDDPRINT("slow path target resolve"));
64192                 func = duk__resolve_target_func_and_this_binding(thr, idx_func, &call_flags);
64193         }
64194         DUK_ASSERT(duk_get_top(thr) - idx_func >= 2);  /* at least func and this present */
64195
64196         DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
64197         DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
64198                                     DUK_HOBJECT_IS_NATFUNC(func)));
64199
64200         /* [ ... func this arg1 ... argN ] */
64201
64202         /*
64203          *  Setup a preliminary activation and figure out nargs/nregs and
64204          *  value stack minimum size.
64205          *
64206          *  Don't touch valstack_bottom or valstack_top yet so that Duktape API
64207          *  calls work normally.
64208          *
64209          *  Because 'act' is not zeroed, all fields must be filled in.
64210          */
64211
64212         /* Should not be necessary, but initialize to silence warnings. */
64213         act = NULL;
64214         nargs = 0;
64215         nregs = 0;
64216         vs_min_bytes = 0;
64217
64218 #if defined(DUK_USE_TAILCALL)
64219         use_tailcall = (call_flags & DUK_CALL_FLAG_TAILCALL);
64220         if (use_tailcall) {
64221                 use_tailcall = duk__call_setup_act_attempt_tailcall(thr,
64222                                                                     call_flags,
64223                                                                     idx_func,
64224                                                                     func,
64225                                                                     entry_valstack_bottom_byteoff,
64226                                                                     entry_valstack_end_byteoff,
64227                                                                     &nargs,
64228                                                                     &nregs,
64229                                                                     &vs_min_bytes,
64230                                                                     &act);
64231         }
64232 #else
64233         DUK_ASSERT((call_flags & DUK_CALL_FLAG_TAILCALL) == 0);  /* compiler ensures this */
64234         use_tailcall = 0;
64235 #endif
64236
64237         if (use_tailcall) {
64238                 idx_args = 0;
64239                 DUK_STATS_INC(thr->heap, stats_call_tailcall);
64240         } else {
64241                 duk__call_setup_act_not_tailcall(thr,
64242                                                  call_flags,
64243                                                  idx_func,
64244                                                  func,
64245                                                  entry_valstack_bottom_byteoff,
64246                                                  entry_valstack_end_byteoff,
64247                                                  &nargs,
64248                                                  &nregs,
64249                                                  &vs_min_bytes,
64250                                                  &act);
64251                 idx_args = idx_func + 2;
64252         }
64253         /* After this point idx_func is no longer valid for tailcalls. */
64254
64255         DUK_ASSERT(act != NULL);
64256
64257         /* [ ... func this arg1 ... argN ] */
64258
64259         /*
64260          *  Environment record creation and 'arguments' object creation.
64261          *  Named function expression name binding is handled by the
64262          *  compiler; the compiled function's parent env will contain
64263          *  the (immutable) binding already.
64264          *
64265          *  This handling is now identical for C and ECMAScript functions.
64266          *  C functions always have the 'NEWENV' flag set, so their
64267          *  environment record initialization is delayed (which is good).
64268          *
64269          *  Delayed creation (on demand) is handled in duk_js_var.c.
64270          */
64271
64272         duk__call_env_setup(thr, func, act, idx_args);
64273
64274         /* [ ... func this arg1 ... argN ] */
64275
64276         /*
64277          *  Setup value stack: clamp to 'nargs', fill up to 'nregs',
64278          *  ensure value stack size matches target requirements, and
64279          *  switch value stack bottom.  Valstack top is kept.
64280          *
64281          *  Value stack can only grow here.
64282          */
64283
64284         duk_valstack_grow_check_throw(thr, vs_min_bytes);
64285         act->reserve_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
64286
64287         if (use_tailcall) {
64288                 DUK_ASSERT(nregs >= 0);
64289                 DUK_ASSERT(nregs >= nargs);
64290                 duk_set_top_and_wipe(thr, nregs, nargs);
64291         } else {
64292                 if (nregs >= 0) {
64293                         DUK_ASSERT(nregs >= nargs);
64294                         duk_set_top_and_wipe(thr, idx_func + 2 + nregs, idx_func + 2 + nargs);
64295                 } else {
64296                         ;
64297                 }
64298                 thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
64299         }
64300         DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
64301         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
64302         DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
64303
64304         /*
64305          *  Make the actual call.  For Ecma-to-Ecma calls detect that
64306          *  setup is complete, then return with a status code that allows
64307          *  the caller to reuse the running executor.
64308          */
64309
64310         if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) {
64311                 /*
64312                  *  ECMAScript call.
64313                  */
64314
64315                 DUK_ASSERT(func != NULL);
64316                 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
64317                 act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
64318
64319                 if (call_flags & DUK_CALL_FLAG_ALLOW_ECMATOECMA) {
64320                         DUK_DD(DUK_DDPRINT("avoid native call, use existing executor"));
64321                         DUK_STATS_INC(thr->heap, stats_call_ecmatoecma);
64322                         DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
64323                         DUK_REFZERO_CHECK_FAST(thr);
64324                         DUK_ASSERT(thr->ptr_curr_pc == NULL);
64325                         return 1;  /* 1=reuse executor */
64326                 }
64327                 DUK_ASSERT(use_tailcall == 0);
64328
64329                 /* duk_hthread_activation_unwind_norz() will decrease this on unwind */
64330                 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
64331                 act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
64332                 thr->callstack_preventcount++;
64333
64334                 /* XXX: we could just do this on entry regardless of reuse, as long
64335                  * as recursion depth is decreased for e2e case.
64336                  */
64337                 duk__call_c_recursion_limit_check(thr);
64338                 thr->heap->call_recursion_depth++;
64339
64340                 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
64341
64342                 /*
64343                  *  Bytecode executor call.
64344                  *
64345                  *  Execute bytecode, handling any recursive function calls and
64346                  *  thread resumptions.  Returns when execution would return from
64347                  *  the entry level activation.  When the executor returns, a
64348                  *  single return value is left on the stack top.
64349                  *
64350                  *  The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
64351                  *  other types are handled internally by the executor.
64352                  */
64353
64354                 /* thr->ptr_curr_pc is set by bytecode executor early on entry */
64355                 DUK_ASSERT(thr->ptr_curr_pc == NULL);
64356                 DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
64357                 duk_js_execute_bytecode(thr);
64358                 DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
64359         } else {
64360                 /*
64361                  *  Native call.
64362                  */
64363
64364                 DUK_ASSERT(func == NULL || ((duk_hnatfunc *) func)->func != NULL);
64365                 DUK_ASSERT(use_tailcall == 0);
64366
64367                 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
64368
64369                 /* duk_hthread_activation_unwind_norz() will decrease this on unwind */
64370                 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
64371                 act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
64372                 thr->callstack_preventcount++;
64373
64374                 /* XXX: we could just do this on entry regardless of reuse, as long
64375                  * as recursion depth is decreased for e2e case.
64376                  */
64377                 duk__call_c_recursion_limit_check(thr);
64378                 thr->heap->call_recursion_depth++;
64379
64380                 /* For native calls must be NULL so we don't sync back */
64381                 DUK_ASSERT(thr->ptr_curr_pc == NULL);
64382
64383                 /* XXX: native funcptr could come out of call setup. */
64384                 if (func) {
64385                         rc = ((duk_hnatfunc *) func)->func(thr);
64386                 } else {
64387                         duk_tval *tv_func;
64388                         duk_c_function funcptr;
64389
64390                         tv_func = &act->tv_func;
64391                         DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
64392                         funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
64393                         rc = funcptr(thr);
64394                 }
64395
64396                 /* Automatic error throwing, retval check. */
64397
64398                 if (rc == 0) {
64399                         DUK_ASSERT(thr->valstack < thr->valstack_end);
64400                         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
64401                         thr->valstack_top++;
64402                 } else if (rc == 1) {
64403                         ;
64404                 } else if (rc < 0) {
64405                         duk_error_throw_from_negative_rc(thr, rc);
64406                         DUK_WO_NORETURN(return 0;);
64407                 } else {
64408                         DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CFUNC_RC);
64409                         DUK_WO_NORETURN(return 0;);
64410                 }
64411         }
64412         DUK_ASSERT(thr->ptr_curr_pc == NULL);
64413         DUK_ASSERT(use_tailcall == 0);
64414
64415         /*
64416          *  Constructor call post processing.
64417          */
64418
64419 #if defined(DUK_USE_ES6_PROXY)
64420         if (call_flags & (DUK_CALL_FLAG_CONSTRUCT | DUK_CALL_FLAG_CONSTRUCT_PROXY)) {
64421                 duk_call_construct_postprocess(thr, call_flags & DUK_CALL_FLAG_CONSTRUCT_PROXY);
64422         }
64423 #else
64424         if (call_flags & DUK_CALL_FLAG_CONSTRUCT) {
64425                 duk_call_construct_postprocess(thr, 0);
64426         }
64427 #endif
64428
64429         /*
64430          *  Unwind, restore valstack bottom and other book-keeping.
64431          */
64432
64433         DUK_ASSERT(thr->callstack_curr != NULL);
64434         DUK_ASSERT(thr->callstack_curr->parent == entry_act);
64435         DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
64436         duk_hthread_activation_unwind_norz(thr);
64437         DUK_ASSERT(thr->callstack_curr == entry_act);
64438         DUK_ASSERT(thr->callstack_top == entry_callstack_top);
64439
64440         thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff);
64441         /* keep current valstack_top */
64442         DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
64443         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
64444         DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
64445         DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
64446
64447         /* Return value handling. */
64448
64449         /* [ ... func this (crud) retval ] */
64450
64451         {
64452                 duk_tval *tv_ret;
64453                 duk_tval *tv_funret;
64454
64455                 tv_ret = thr->valstack_bottom + idx_func;
64456                 tv_funret = thr->valstack_top - 1;
64457 #if defined(DUK_USE_FASTINT)
64458                 /* Explicit check for fastint downgrade. */
64459                 DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret);
64460 #endif
64461                 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret);  /* side effects */
64462         }
64463
64464         duk_set_top_unsafe(thr, idx_func + 1);
64465
64466         /* [ ... retval ] */
64467
64468         /* Restore caller's value stack reserve (cannot fail). */
64469         DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff >= (duk_uint8_t *) thr->valstack_top);
64470         DUK_ASSERT((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff <= (duk_uint8_t *) thr->valstack_alloc_end);
64471         thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_end_byteoff);
64472
64473         /* XXX: Trial value stack shrink would be OK here, but we'd need
64474          * to prevent side effects of the potential realloc.
64475          */
64476
64477         /* Restore entry thread executor curr_pc stack frame pointer. */
64478         thr->ptr_curr_pc = entry_ptr_curr_pc;
64479
64480         DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread);  /* may be NULL */
64481         thr->state = (duk_uint8_t) entry_thread_state;
64482
64483         /* Disabled assert: triggered with some torture tests. */
64484 #if 0
64485         DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) ||  /* first call */
64486                    (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) ||  /* other call */
64487                    (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr));     /* current thread */
64488 #endif
64489
64490         thr->heap->call_recursion_depth = entry_call_recursion_depth;
64491
64492         /* If the debugger is active we need to force an interrupt so that
64493          * debugger breakpoints are rechecked.  This is important for function
64494          * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
64495          * GH-303.  Only needed for success path, error path always causes a
64496          * breakpoint recheck in the executor.  It would be enough to set this
64497          * only when returning to an ECMAScript activation, but setting the flag
64498          * on every return should have no ill effect.
64499          */
64500 #if defined(DUK_USE_DEBUGGER_SUPPORT)
64501         if (duk_debug_is_attached(thr->heap)) {
64502                 DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
64503                 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
64504                 thr->interrupt_init -= thr->interrupt_counter;
64505                 thr->interrupt_counter = 0;
64506                 thr->heap->dbg_force_restart = 1;
64507         }
64508 #endif
64509
64510 #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
64511         duk__interrupt_fixup(thr, entry_curr_thread);
64512 #endif
64513
64514         /* Restored by success path. */
64515         DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
64516         DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
64517         DUK_ASSERT_LJSTATE_UNSET(thr->heap);
64518
64519         DUK_REFZERO_CHECK_FAST(thr);
64520
64521         return 0;  /* 0=call handled inline */
64522 }
64523
64524 DUK_INTERNAL duk_int_t duk_handle_call_unprotected_nargs(duk_hthread *thr,
64525                                                          duk_idx_t nargs,
64526                                                          duk_small_uint_t call_flags) {
64527         duk_idx_t idx_func;
64528         DUK_ASSERT(duk_get_top(thr) >= nargs + 2);
64529         idx_func = duk_get_top(thr) - (nargs + 2);
64530         DUK_ASSERT(idx_func >= 0);
64531         return duk_handle_call_unprotected(thr, idx_func, call_flags);
64532 }
64533
64534 DUK_INTERNAL duk_int_t duk_handle_call_unprotected(duk_hthread *thr,
64535                                                    duk_idx_t idx_func,
64536                                                    duk_small_uint_t call_flags) {
64537         DUK_ASSERT(duk_is_valid_index(thr, idx_func));
64538         DUK_ASSERT(idx_func >= 0);
64539         return duk__handle_call_raw(thr, idx_func, call_flags);
64540 }
64541
64542 /*
64543  *  duk_handle_safe_call(): make a "C protected call" within the
64544  *  current activation.
64545  *
64546  *  The allowed thread states for making a call are the same as for
64547  *  duk_handle_call_protected().
64548  *
64549  *  Even though this call is protected, errors are thrown for insane arguments
64550  *  and may result in a fatal error unless there's another protected call which
64551  *  catches such errors.
64552  *
64553  *  The error handling path should be error free, even for out-of-memory
64554  *  errors, to ensure safe sandboxing.  (As of Duktape 2.2.0 this is not
64555  *  yet the case for environment closing which may run out of memory, see
64556  *  XXX notes below.)
64557  */
64558
64559 DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
64560                                            duk_safe_call_function func,
64561                                            void *udata,
64562 #if defined(DUK_USE_ASSERTIONS)
64563                                            duk_size_t entry_valstack_bottom_byteoff,
64564                                            duk_size_t entry_callstack_top,
64565 #endif
64566                                            duk_hthread *entry_curr_thread,
64567                                            duk_uint_fast8_t entry_thread_state,
64568                                            duk_idx_t idx_retbase,
64569                                            duk_idx_t num_stack_rets) {
64570         duk_ret_t rc;
64571
64572         DUK_ASSERT(thr != NULL);
64573         DUK_ASSERT_CTX_VALID(thr);
64574
64575         /*
64576          *  Thread state check and book-keeping.
64577          */
64578
64579         duk__call_thread_state_update(thr);
64580
64581         /*
64582          *  Recursion limit check.
64583          */
64584
64585         duk__call_c_recursion_limit_check(thr);
64586         thr->heap->call_recursion_depth++;
64587
64588         /*
64589          *  Make the C call.
64590          */
64591
64592         rc = func(thr, udata);
64593
64594         DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
64595
64596         /*
64597          *  Valstack manipulation for results.
64598          */
64599
64600         /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
64601         DUK_ASSERT(thr->callstack_top == entry_callstack_top);
64602         DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
64603         DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff);
64604         DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
64605         DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
64606
64607         if (DUK_UNLIKELY(rc < 0)) {
64608                 duk_error_throw_from_negative_rc(thr, rc);
64609                 DUK_WO_NORETURN(return;);
64610         }
64611         DUK_ASSERT(rc >= 0);
64612
64613         duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);  /* throws for insane rc */
64614
64615         DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread);  /* may be NULL */
64616         thr->state = (duk_uint8_t) entry_thread_state;
64617 }
64618
64619 DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
64620                                            duk_activation *entry_act,
64621 #if defined(DUK_USE_ASSERTIONS)
64622                                            duk_size_t entry_callstack_top,
64623 #endif
64624                                            duk_hthread *entry_curr_thread,
64625                                            duk_uint_fast8_t entry_thread_state,
64626                                            duk_idx_t idx_retbase,
64627                                            duk_idx_t num_stack_rets,
64628                                            duk_size_t entry_valstack_bottom_byteoff,
64629                                            duk_jmpbuf *old_jmpbuf_ptr) {
64630         DUK_ASSERT(thr != NULL);
64631         DUK_ASSERT_CTX_VALID(thr);
64632
64633         /*
64634          *  Error during call.  The error value is at heap->lj.value1.
64635          *
64636          *  The very first thing we do is restore the previous setjmp catcher.
64637          *  This means that any error in error handling will propagate outwards
64638          *  instead of causing a setjmp() re-entry above.
64639          */
64640
64641         DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
64642
64643         /* Other longjmp types are handled by executor before propagating
64644          * the error here.
64645          */
64646         DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
64647         DUK_ASSERT_LJSTATE_SET(thr->heap);
64648
64649         /* Either pointer may be NULL (at entry), so don't assert. */
64650         thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
64651
64652         /* XXX: callstack unwind may now throw an error when closing
64653          * scopes; this is a sandboxing issue, described in:
64654          * https://github.com/svaarala/duktape/issues/476
64655          */
64656         /* XXX: "unwind to" primitive? */
64657
64658         DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
64659         while (thr->callstack_curr != entry_act) {
64660                 DUK_ASSERT(thr->callstack_curr != NULL);
64661                 duk_hthread_activation_unwind_norz(thr);
64662         }
64663         DUK_ASSERT(thr->callstack_top == entry_callstack_top);
64664
64665         /* Switch active thread before any side effects to avoid a
64666          * dangling curr_thread pointer.
64667          */
64668         DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread);  /* may be NULL */
64669         thr->state = (duk_uint8_t) entry_thread_state;
64670
64671         DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread);
64672         DUK_ASSERT(thr->state == entry_thread_state);
64673
64674         /* Restore valstack bottom. */
64675         thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + entry_valstack_bottom_byteoff);
64676
64677         /* [ ... | (crud) ] */
64678
64679         /* XXX: ensure space in valstack (now relies on internal reserve)? */
64680         duk_push_tval(thr, &thr->heap->lj.value1);
64681
64682         /* [ ... | (crud) errobj ] */
64683
64684         DUK_ASSERT(duk_get_top(thr) >= 1);  /* at least errobj must be on stack */
64685
64686         duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1);  /* 1 = num actual 'return values' */
64687
64688         /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
64689
64690         /* Reset longjmp state. */
64691         thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
64692         thr->heap->lj.iserror = 0;
64693         DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value1);
64694         DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, &thr->heap->lj.value2);
64695
64696         /* Error handling complete, remove side effect protections.  Caller
64697          * will process pending finalizers.
64698          */
64699 #if defined(DUK_USE_ASSERTIONS)
64700         DUK_ASSERT(thr->heap->error_not_allowed == 1);
64701         thr->heap->error_not_allowed = 0;
64702 #endif
64703         DUK_ASSERT(thr->heap->pf_prevent_count > 0);
64704         thr->heap->pf_prevent_count--;
64705         DUK_DD(DUK_DDPRINT("safe call error handled, pf_prevent_count updated to %ld", (long) thr->heap->pf_prevent_count));
64706
64707         /* thr->ptr_curr_pc is restored by
64708          * duk__handle_safe_call_shared_unwind() which is also used for
64709          * success path.
64710          */
64711 }
64712
64713 DUK_LOCAL void duk__handle_safe_call_shared_unwind(duk_hthread *thr,
64714                                                    duk_idx_t idx_retbase,
64715                                                    duk_idx_t num_stack_rets,
64716 #if defined(DUK_USE_ASSERTIONS)
64717                                                    duk_size_t entry_callstack_top,
64718 #endif
64719                                                    duk_int_t entry_call_recursion_depth,
64720                                                    duk_hthread *entry_curr_thread,
64721                                                    duk_instr_t **entry_ptr_curr_pc) {
64722         DUK_ASSERT(thr != NULL);
64723         DUK_ASSERT_CTX_VALID(thr);
64724         DUK_UNREF(idx_retbase);
64725         DUK_UNREF(num_stack_rets);
64726         DUK_UNREF(entry_curr_thread);
64727
64728         DUK_ASSERT(thr->callstack_top == entry_callstack_top);
64729
64730         /* Restore entry thread executor curr_pc stack frame pointer.
64731          * XXX: would be enough to do in error path only, should nest
64732          * cleanly in success path.
64733          */
64734         thr->ptr_curr_pc = entry_ptr_curr_pc;
64735
64736         thr->heap->call_recursion_depth = entry_call_recursion_depth;
64737
64738         /* stack discipline consistency check */
64739         DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets);
64740
64741         /* A debugger forced interrupt check is not needed here, as
64742          * problematic safe calls are not caused by side effects.
64743          */
64744
64745 #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
64746         duk__interrupt_fixup(thr, entry_curr_thread);
64747 #endif
64748 }
64749
64750 DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
64751                                             duk_safe_call_function func,
64752                                             void *udata,
64753                                             duk_idx_t num_stack_args,
64754                                             duk_idx_t num_stack_rets) {
64755         duk_activation *entry_act;
64756         duk_size_t entry_valstack_bottom_byteoff;
64757 #if defined(DUK_USE_ASSERTIONS)
64758         duk_size_t entry_valstack_end_byteoff;
64759         duk_size_t entry_callstack_top;
64760         duk_size_t entry_callstack_preventcount;
64761 #endif
64762         duk_int_t entry_call_recursion_depth;
64763         duk_hthread *entry_curr_thread;
64764         duk_uint_fast8_t entry_thread_state;
64765         duk_instr_t **entry_ptr_curr_pc;
64766         duk_jmpbuf *old_jmpbuf_ptr = NULL;
64767         duk_jmpbuf our_jmpbuf;
64768         duk_idx_t idx_retbase;
64769         duk_int_t retval;
64770
64771         DUK_ASSERT(thr != NULL);
64772         DUK_ASSERT(duk_get_top(thr) >= num_stack_args);  /* Caller ensures. */
64773
64774         DUK_STATS_INC(thr->heap, stats_safecall_all);
64775
64776         /* Value stack reserve handling: safe call assumes caller has reserved
64777          * space for nrets (assuming optimal unwind processing).  Value stack
64778          * reserve is not stored/restored as for normal calls because a safe
64779          * call conceptually happens in the same activation.
64780          */
64781
64782         /* Careful with indices like '-x'; if 'x' is zero, it refers to bottom */
64783         entry_act = thr->callstack_curr;
64784         entry_valstack_bottom_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack);
64785 #if defined(DUK_USE_ASSERTIONS)
64786         entry_valstack_end_byteoff = (duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack);
64787         entry_callstack_top = thr->callstack_top;
64788         entry_callstack_preventcount = thr->callstack_preventcount;
64789 #endif
64790         entry_call_recursion_depth = thr->heap->call_recursion_depth;
64791         entry_curr_thread = thr->heap->curr_thread;  /* may be NULL if first call */
64792         entry_thread_state = thr->state;
64793         entry_ptr_curr_pc = thr->ptr_curr_pc;  /* may be NULL */
64794         idx_retbase = duk_get_top(thr) - num_stack_args;  /* not a valid stack index if num_stack_args == 0 */
64795         DUK_ASSERT(idx_retbase >= 0);
64796
64797         DUK_ASSERT((duk_idx_t) (thr->valstack_top - thr->valstack_bottom) >= num_stack_args);  /* Caller ensures. */
64798         DUK_ASSERT((duk_idx_t) (thr->valstack_end - (thr->valstack_bottom + idx_retbase)) >= num_stack_rets);  /* Caller ensures. */
64799
64800         /* Cannot portably debug print a function pointer, hence 'func' not printed! */
64801         DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
64802                            "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
64803                            "entry_act=%p, entry_valstack_bottom_byteoff=%ld, entry_call_recursion_depth=%ld, "
64804                            "entry_curr_thread=%p, entry_thread_state=%ld",
64805                            (void *) thr,
64806                            (long) num_stack_args,
64807                            (long) num_stack_rets,
64808                            (long) duk_get_top(thr),
64809                            (long) idx_retbase,
64810                            (long) thr->heap->call_recursion_depth,
64811                            (long) thr->heap->call_recursion_limit,
64812                            (void *) entry_act,
64813                            (long) entry_valstack_bottom_byteoff,
64814                            (long) entry_call_recursion_depth,
64815                            (void *) entry_curr_thread,
64816                            (long) entry_thread_state));
64817
64818         /* Setjmp catchpoint setup. */
64819         old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
64820         thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
64821
64822         /* Prevent yields for the duration of the safe call.  This only
64823          * matters if the executor makes safe calls to functions that
64824          * yield, this doesn't currently happen.
64825          */
64826         thr->callstack_preventcount++;
64827
64828 #if defined(DUK_USE_CPP_EXCEPTIONS)
64829         try {
64830 #else
64831         DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
64832         if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
64833                 /* Success path. */
64834 #endif
64835                 DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
64836
64837                 duk__handle_safe_call_inner(thr,
64838                                             func,
64839                                             udata,
64840 #if defined(DUK_USE_ASSERTIONS)
64841                                             entry_valstack_bottom_byteoff,
64842                                             entry_callstack_top,
64843 #endif
64844                                             entry_curr_thread,
64845                                             entry_thread_state,
64846                                             idx_retbase,
64847                                             num_stack_rets);
64848
64849                 DUK_STATS_INC(thr->heap, stats_safecall_nothrow);
64850
64851                 /* Either pointer may be NULL (at entry), so don't assert */
64852                 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
64853
64854                 /* If calls happen inside the safe call, these are restored by
64855                  * whatever calls are made.  Reserve cannot decrease.
64856                  */
64857                 DUK_ASSERT(thr->callstack_curr == entry_act);
64858                 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
64859
64860                 retval = DUK_EXEC_SUCCESS;
64861 #if defined(DUK_USE_CPP_EXCEPTIONS)
64862         } catch (duk_internal_exception &exc) {
64863                 DUK_UNREF(exc);
64864 #else
64865         } else {
64866                 /* Error path. */
64867 #endif
64868                 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
64869
64870                 DUK_STATS_INC(thr->heap, stats_safecall_throw);
64871
64872                 duk__handle_safe_call_error(thr,
64873                                             entry_act,
64874 #if defined(DUK_USE_ASSERTIONS)
64875                                             entry_callstack_top,
64876 #endif
64877                                             entry_curr_thread,
64878                                             entry_thread_state,
64879                                             idx_retbase,
64880                                             num_stack_rets,
64881                                             entry_valstack_bottom_byteoff,
64882                                             old_jmpbuf_ptr);
64883
64884                 retval = DUK_EXEC_ERROR;
64885         }
64886 #if defined(DUK_USE_CPP_EXCEPTIONS)
64887         catch (duk_fatal_exception &exc) {
64888                 DUK_D(DUK_DPRINT("rethrow duk_fatal_exception"));
64889                 throw;
64890         } catch (std::exception &exc) {
64891                 const char *what = exc.what();
64892                 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
64893                 DUK_STATS_INC(thr->heap, stats_safecall_throw);
64894                 if (!what) {
64895                         what = "unknown";
64896                 }
64897                 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
64898                 try {
64899                         DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
64900                         DUK_WO_NORETURN(return 0;);
64901                 } catch (duk_internal_exception exc) {
64902                         DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
64903                         DUK_UNREF(exc);
64904                         duk__handle_safe_call_error(thr,
64905                                                     entry_act,
64906 #if defined(DUK_USE_ASSERTIONS)
64907                                                     entry_callstack_top,
64908 #endif
64909                                                     entry_curr_thread,
64910                                                     entry_thread_state,
64911                                                     idx_retbase,
64912                                                     num_stack_rets,
64913                                                     entry_valstack_bottom_byteoff,
64914                                                     old_jmpbuf_ptr);
64915                         retval = DUK_EXEC_ERROR;
64916                 }
64917         } catch (...) {
64918                 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
64919                 DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
64920                 DUK_STATS_INC(thr->heap, stats_safecall_throw);
64921                 try {
64922                         DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
64923                         DUK_WO_NORETURN(return 0;);
64924                 } catch (duk_internal_exception exc) {
64925                         DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
64926                         DUK_UNREF(exc);
64927                         duk__handle_safe_call_error(thr,
64928                                                     entry_act,
64929 #if defined(DUK_USE_ASSERTIONS)
64930                                                     entry_callstack_top,
64931 #endif
64932                                                     entry_curr_thread,
64933                                                     entry_thread_state,
64934                                                     idx_retbase,
64935                                                     num_stack_rets,
64936                                                     entry_valstack_bottom_byteoff,
64937                                                     old_jmpbuf_ptr);
64938                         retval = DUK_EXEC_ERROR;
64939                 }
64940         }
64941 #endif
64942
64943         DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr);  /* success/error path both do this */
64944
64945         DUK_ASSERT_LJSTATE_UNSET(thr->heap);
64946
64947         DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
64948         duk__handle_safe_call_shared_unwind(thr,
64949                                             idx_retbase,
64950                                             num_stack_rets,
64951 #if defined(DUK_USE_ASSERTIONS)
64952                                             entry_callstack_top,
64953 #endif
64954                                             entry_call_recursion_depth,
64955                                             entry_curr_thread,
64956                                             entry_ptr_curr_pc);
64957
64958         /* Restore preventcount. */
64959         thr->callstack_preventcount--;
64960         DUK_ASSERT(thr->callstack_preventcount == entry_callstack_preventcount);
64961
64962         /* Final asserts. */
64963         DUK_ASSERT(thr->callstack_curr == entry_act);
64964         DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_bottom - (duk_uint8_t *) thr->valstack) == entry_valstack_bottom_byteoff);
64965         DUK_ASSERT((duk_size_t) ((duk_uint8_t *) thr->valstack_end - (duk_uint8_t *) thr->valstack) >= entry_valstack_end_byteoff);
64966         DUK_ASSERT(thr->callstack_top == entry_callstack_top);
64967         DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
64968         DUK_ASSERT(thr->heap->curr_thread == entry_curr_thread);
64969         DUK_ASSERT(thr->state == entry_thread_state);
64970         DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
64971         DUK_ASSERT(duk_get_top(thr) == idx_retbase + num_stack_rets);
64972         DUK_ASSERT_LJSTATE_UNSET(thr->heap);
64973
64974         /* Pending side effects. */
64975         DUK_REFZERO_CHECK_FAST(thr);
64976
64977         return retval;
64978 }
64979
64980 /*
64981  *  Property-based call (foo.noSuch()) error setup: replace target function
64982  *  on stack top with a specially tagged (hidden Symbol) error which gets
64983  *  thrown in call handling at the proper spot to follow ECMAScript semantics.
64984  */
64985
64986 #if defined(DUK_USE_VERBOSE_ERRORS)
64987 DUK_INTERNAL DUK_NOINLINE DUK_COLD void duk_call_setup_propcall_error(duk_hthread *thr, duk_tval *tv_targ, duk_tval *tv_base, duk_tval *tv_key) {
64988         const char *str1, *str2, *str3;
64989         duk_idx_t entry_top;
64990
64991         entry_top = duk_get_top(thr);
64992
64993         /* Must stabilize pointers first.  Argument convention is a bit awkward,
64994          * it comes from the executor call site where some arguments may not be
64995          * on the value stack (consts).
64996          */
64997         duk_push_tval(thr, tv_base);
64998         duk_push_tval(thr, tv_key);
64999         duk_push_tval(thr, tv_targ);
65000
65001         DUK_GC_TORTURE(thr->heap);
65002
65003         /* We only push an error, replacing the call target (at idx_func)
65004          * with the error to ensure side effects come out correctly:
65005          * - Property read
65006          * - Call argument evaluation
65007          * - Callability check and error thrown.
65008          *
65009          * A hidden Symbol on the error object pushed here is used by
65010          * call handling to figure out the error is to be thrown as is.
65011          * It is CRITICAL that the hidden Symbol can never occur on a
65012          * user visible object that may get thrown.
65013          */
65014
65015 #if defined(DUK_USE_PARANOID_ERRORS)
65016         str1 = duk_get_type_name(thr, -1);
65017         str2 = duk_get_type_name(thr, -2);
65018         str3 = duk_get_type_name(thr, -3);
65019         duk_push_error_object(thr, DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, "%s not callable (property %s of %s)", str1, str2, str3);
65020 #else
65021         str1 = duk_push_string_readable(thr, -1);
65022         str2 = duk_push_string_readable(thr, -3);
65023         str3 = duk_push_string_readable(thr, -5);
65024         duk_push_error_object(thr, DUK_ERR_TYPE_ERROR | DUK_ERRCODE_FLAG_NOBLAME_FILELINE, "%s not callable (property %s of %s)", str1, str2, str3);
65025 #endif
65026
65027         duk_push_true(thr);
65028         duk_put_prop_stridx(thr, -2, DUK_STRIDX_INT_TARGET);  /* Marker property, reuse _Target. */
65029
65030         /* [ <nregs> propValue <variable> error ] */
65031         duk_replace(thr, entry_top - 1);
65032         duk_set_top(thr, entry_top);
65033
65034         DUK_ASSERT(!duk_is_callable(thr, -1));  /* Critical so that call handling will throw the error. */
65035 }
65036 #endif  /* DUK_USE_VERBOSE_ERRORS */
65037
65038 /* automatic undefs */
65039 #undef DUK__AUGMENT_CALL_RELAX_COUNT
65040 #line 1 "duk_js_compiler.c"
65041 /*
65042  *  ECMAScript compiler.
65043  *
65044  *  Parses an input string and generates a function template result.
65045  *  Compilation may happen in multiple contexts (global code, eval
65046  *  code, function code).
65047  *
65048  *  The parser uses a traditional top-down recursive parsing for the
65049  *  statement level, and an operator precedence based top-down approach
65050  *  for the expression level.  The attempt is to minimize the C stack
65051  *  depth.  Bytecode is generated directly without an intermediate
65052  *  representation (tree), at the cost of needing two (and sometimes
65053  *  three) passes over each function.
65054  *
65055  *  The top-down recursive parser functions are named "duk__parse_XXX".
65056  *
65057  *  Recursion limits are in key functions to prevent arbitrary C recursion:
65058  *  function body parsing, statement parsing, and expression parsing.
65059  *
65060  *  See doc/compiler.rst for discussion on the design.
65061  *
65062  *  A few typing notes:
65063  *
65064  *    - duk_regconst_t: signed, highest bit set (< 0) means constant,
65065  *      some call sites use -1 for "none" (equivalent to constant 0x7fffffff)
65066  *    - PC values: duk_int_t, negative values used as markers
65067  */
65068
65069 /* #include duk_internal.h -> already included */
65070
65071 /* If highest bit of a register number is set, it refers to a constant instead.
65072  * When interpreted as a signed value, this means const values are always
65073  * negative (when interpreted as two's complement).  For example DUK__ISREG_TEMP()
65074  * uses this approach to avoid an explicit DUK__ISREG() check (the condition is
65075  * logically "'x' is a register AND 'x' >= temp_first").
65076  */
65077 #define DUK__CONST_MARKER                   DUK_REGCONST_CONST_MARKER
65078 #define DUK__REMOVECONST(x)                 ((x) & ~DUK__CONST_MARKER)
65079 #define DUK__ISREG(x)                       ((x) >= 0)
65080 #define DUK__ISCONST(x)                     ((x) < 0)
65081 #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. */
65082 #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. */
65083 #define DUK__GETTEMP(comp_ctx)              ((comp_ctx)->curr_func.temp_next)
65084 #define DUK__SETTEMP(comp_ctx,x)            ((comp_ctx)->curr_func.temp_next = (x))  /* dangerous: must only lower (temp_max not updated) */
65085 #define DUK__SETTEMP_CHECKMAX(comp_ctx,x)   duk__settemp_checkmax((comp_ctx),(x))
65086 #define DUK__ALLOCTEMP(comp_ctx)            duk__alloctemp((comp_ctx))
65087 #define DUK__ALLOCTEMPS(comp_ctx,count)     duk__alloctemps((comp_ctx),(count))
65088
65089 /* Init value set size for array and object literals. */
65090 #define DUK__MAX_ARRAY_INIT_VALUES        20
65091 #define DUK__MAX_OBJECT_INIT_PAIRS        10
65092
65093 /* XXX: hack, remove when const lookup is not O(n) */
65094 #define DUK__GETCONST_MAX_CONSTS_CHECK    256
65095
65096 /* These limits are based on bytecode limits.  Max temps is limited
65097  * by duk_hcompfunc nargs/nregs fields being 16 bits.
65098  */
65099 #define DUK__MAX_CONSTS                   DUK_BC_BC_MAX
65100 #define DUK__MAX_FUNCS                    DUK_BC_BC_MAX
65101 #define DUK__MAX_TEMPS                    0xffffL
65102
65103 /* Initial bytecode size allocation. */
65104 #if defined(DUK_USE_PREFER_SIZE)
65105 #define DUK__BC_INITIAL_INSTS             16
65106 #else
65107 #define DUK__BC_INITIAL_INSTS             256
65108 #endif
65109
65110 #define DUK__RECURSION_INCREASE(comp_ctx,thr)  do { \
65111                 DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
65112                 duk__comp_recursion_increase((comp_ctx)); \
65113         } while (0)
65114
65115 #define DUK__RECURSION_DECREASE(comp_ctx,thr)  do { \
65116                 DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
65117                 duk__comp_recursion_decrease((comp_ctx)); \
65118         } while (0)
65119
65120 /* Value stack slot limits: these are quite approximate right now, and
65121  * because they overlap in control flow, some could be eliminated.
65122  */
65123 #define DUK__COMPILE_ENTRY_SLOTS          8
65124 #define DUK__FUNCTION_INIT_REQUIRE_SLOTS  16
65125 #define DUK__FUNCTION_BODY_REQUIRE_SLOTS  16
65126 #define DUK__PARSE_STATEMENTS_SLOTS       16
65127 #define DUK__PARSE_EXPR_SLOTS             16
65128
65129 /* Temporary structure used to pass a stack allocated region through
65130  * duk_safe_call().
65131  */
65132 typedef struct {
65133         duk_small_uint_t flags;
65134         duk_compiler_ctx comp_ctx_alloc;
65135         duk_lexer_point lex_pt_alloc;
65136 } duk__compiler_stkstate;
65137
65138 /*
65139  *  Prototypes
65140  */
65141
65142 /* lexing */
65143 DUK_LOCAL_DECL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
65144 DUK_LOCAL_DECL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
65145 DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx);
65146
65147 /* function helpers */
65148 DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
65149 DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
65150 DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg);
65151 DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx);
65152 DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
65153
65154 /* code emission */
65155 DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx);
65156 DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc);
65157 DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins);
65158 DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op);
65159 DUK_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);
65160 DUK_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);
65161 DUK_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);
65162 #if 0  /* unused */
65163 DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
65164 DUK_LOCAL_DECL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b);
65165 #endif
65166 DUK_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);
65167 DUK_LOCAL_DECL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc);
65168 DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc);
65169 DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val);
65170 DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val);
65171 DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
65172 DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
65173 DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
65174 DUK_LOCAL_DECL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc);
65175 DUK_LOCAL_DECL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
65176 DUK_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);
65177 DUK_LOCAL_DECL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
65178 DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
65179 DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx);
65180
65181 /* ivalue/ispec helpers */
65182 DUK_LOCAL_DECL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst);
65183 DUK_LOCAL_DECL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
65184 DUK_LOCAL_DECL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
65185 DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h);
65186 DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
65187 DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
65188 DUK_LOCAL_DECL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
65189 DUK_LOCAL_DECL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
65190 DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next);
65191 DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx);
65192 DUK_LOCAL_DECL
65193 duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
65194                                          duk_ispec *x,
65195                                          duk_regconst_t forced_reg,
65196                                          duk_small_uint_t flags);
65197 DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg);
65198 DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg);
65199 DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
65200 DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
65201 DUK_LOCAL_DECL
65202 duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
65203                                           duk_ivalue *x,
65204                                           duk_regconst_t forced_reg,
65205                                           duk_small_uint_t flags);
65206 DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
65207 #if 0  /* unused */
65208 DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
65209 #endif
65210 DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg);
65211 DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
65212 DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
65213
65214 /* identifier handling */
65215 DUK_LOCAL_DECL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
65216 DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
65217
65218 /* label handling */
65219 DUK_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);
65220 DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags);
65221 DUK_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);
65222 DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len);
65223
65224 /* top-down expression parser */
65225 DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65226 DUK_LOCAL_DECL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res);
65227 DUK_LOCAL_DECL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx);
65228 DUK_LOCAL_DECL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx);
65229
65230 /* exprtop is the top level variant which resets nud/led counts */
65231 DUK_LOCAL_DECL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65232 DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65233
65234 /* convenience helpers */
65235 #if 0  /* unused */
65236 DUK_LOCAL_DECL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65237 #endif
65238 #if 0  /* unused */
65239 DUK_LOCAL_DECL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65240 #endif
65241 DUK_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);
65242 DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65243 #if 0  /* unused */
65244 DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65245 #endif
65246 DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65247 DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65248 DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65249 #if 0  /* unused */
65250 DUK_LOCAL_DECL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65251 #endif
65252 DUK_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);
65253 DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65254 #if 0  /* unused */
65255 DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
65256 #endif
65257
65258 /* expression parsing helpers */
65259 DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65260 DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65261 DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65262
65263 /* statement parsing */
65264 DUK_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);
65265 DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags);
65266 DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
65267 DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
65268 DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65269 DUK_LOCAL_DECL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
65270 DUK_LOCAL_DECL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
65271 DUK_LOCAL_DECL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65272 DUK_LOCAL_DECL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65273 DUK_LOCAL_DECL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65274 DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65275 DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
65276 DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem);
65277 DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id);
65278 DUK_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);
65279
65280 DUK_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);
65281 DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
65282 DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
65283 DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
65284
65285 #define DUK__FUNC_FLAG_DECL            (1 << 0)   /* Parsing a function declaration. */
65286 #define DUK__FUNC_FLAG_GETSET          (1 << 1)   /* Parsing an object literal getter/setter. */
65287 #define DUK__FUNC_FLAG_METDEF          (1 << 2)   /* Parsing an object literal method definition shorthand. */
65288 #define DUK__FUNC_FLAG_PUSHNAME_PASS1  (1 << 3)   /* Push function name when creating template (first pass only). */
65289 #define DUK__FUNC_FLAG_USE_PREVTOKEN   (1 << 4)   /* Use prev_token to start function parsing (workaround for object literal). */
65290
65291 /*
65292  *  Parser control values for tokens.  The token table is ordered by the
65293  *  DUK_TOK_XXX defines.
65294  *
65295  *  The binding powers are for lbp() use (i.e. for use in led() context).
65296  *  Binding powers are positive for typing convenience, and bits at the
65297  *  top should be reserved for flags.  Binding power step must be higher
65298  *  than 1 so that binding power "lbp - 1" can be used for right associative
65299  *  operators.  Currently a step of 2 is used (which frees one more bit for
65300  *  flags).
65301  */
65302
65303 /* XXX: actually single step levels would work just fine, clean up */
65304
65305 /* binding power "levels" (see doc/compiler.rst) */
65306 #define DUK__BP_INVALID                0             /* always terminates led() */
65307 #define DUK__BP_EOF                    2
65308 #define DUK__BP_CLOSING                4             /* token closes expression, e.g. ')', ']' */
65309 #define DUK__BP_FOR_EXPR               DUK__BP_CLOSING    /* bp to use when parsing a top level Expression */
65310 #define DUK__BP_COMMA                  6
65311 #define DUK__BP_ASSIGNMENT             8
65312 #define DUK__BP_CONDITIONAL            10
65313 #define DUK__BP_LOR                    12
65314 #define DUK__BP_LAND                   14
65315 #define DUK__BP_BOR                    16
65316 #define DUK__BP_BXOR                   18
65317 #define DUK__BP_BAND                   20
65318 #define DUK__BP_EQUALITY               22
65319 #define DUK__BP_RELATIONAL             24
65320 #define DUK__BP_SHIFT                  26
65321 #define DUK__BP_ADDITIVE               28
65322 #define DUK__BP_MULTIPLICATIVE         30
65323 #define DUK__BP_EXPONENTIATION         32
65324 #define DUK__BP_POSTFIX                34
65325 #define DUK__BP_CALL                   36
65326 #define DUK__BP_MEMBER                 38
65327
65328 #define DUK__TOKEN_LBP_BP_MASK         0x1f
65329 #define DUK__TOKEN_LBP_FLAG_NO_REGEXP  (1 << 5)   /* regexp literal must not follow this token */
65330 #define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6)   /* terminates expression; e.g. post-increment/-decrement */
65331 #define DUK__TOKEN_LBP_FLAG_UNUSED     (1 << 7)   /* unused */
65332
65333 #define DUK__TOKEN_LBP_GET_BP(x)       ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
65334
65335 #define DUK__MK_LBP(bp)                ((bp) >> 1)    /* bp is assumed to be even */
65336 #define DUK__MK_LBP_FLAGS(bp,flags)    (((bp) >> 1) | (flags))
65337
65338 DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
65339         DUK__MK_LBP(DUK__BP_EOF),                                 /* DUK_TOK_EOF */
65340         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_IDENTIFIER */
65341         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_BREAK */
65342         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CASE */
65343         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CATCH */
65344         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CONTINUE */
65345         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_DEBUGGER */
65346         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_DEFAULT */
65347         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_DELETE */
65348         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_DO */
65349         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_ELSE */
65350         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_FINALLY */
65351         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_FOR */
65352         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_FUNCTION */
65353         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_IF */
65354         DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_IN */
65355         DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_INSTANCEOF */
65356         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_NEW */
65357         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_RETURN */
65358         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_SWITCH */
65359         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_THIS */
65360         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_THROW */
65361         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_TRY */
65362         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_TYPEOF */
65363         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_VAR */
65364         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CONST */
65365         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_VOID */
65366         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_WHILE */
65367         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_WITH */
65368         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_CLASS */
65369         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_ENUM */
65370         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_EXPORT */
65371         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_EXTENDS */
65372         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_IMPORT */
65373         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_SUPER */
65374         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_NULL */
65375         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_TRUE */
65376         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_FALSE */
65377         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_GET */
65378         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_SET */
65379         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_IMPLEMENTS */
65380         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_INTERFACE */
65381         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_LET */
65382         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_PACKAGE */
65383         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_PRIVATE */
65384         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_PROTECTED */
65385         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_PUBLIC */
65386         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_STATIC */
65387         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_YIELD */
65388         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_LCURLY */
65389         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_RCURLY */
65390         DUK__MK_LBP(DUK__BP_MEMBER),                              /* DUK_TOK_LBRACKET */
65391         DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_RBRACKET */
65392         DUK__MK_LBP(DUK__BP_CALL),                                /* DUK_TOK_LPAREN */
65393         DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_RPAREN */
65394         DUK__MK_LBP(DUK__BP_MEMBER),                              /* DUK_TOK_PERIOD */
65395         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_SEMICOLON */
65396         DUK__MK_LBP(DUK__BP_COMMA),                               /* DUK_TOK_COMMA */
65397         DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_LT */
65398         DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_GT */
65399         DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_LE */
65400         DUK__MK_LBP(DUK__BP_RELATIONAL),                          /* DUK_TOK_GE */
65401         DUK__MK_LBP(DUK__BP_EQUALITY),                            /* DUK_TOK_EQ */
65402         DUK__MK_LBP(DUK__BP_EQUALITY),                            /* DUK_TOK_NEQ */
65403         DUK__MK_LBP(DUK__BP_EQUALITY),                            /* DUK_TOK_SEQ */
65404         DUK__MK_LBP(DUK__BP_EQUALITY),                            /* DUK_TOK_SNEQ */
65405         DUK__MK_LBP(DUK__BP_ADDITIVE),                            /* DUK_TOK_ADD */
65406         DUK__MK_LBP(DUK__BP_ADDITIVE),                            /* DUK_TOK_SUB */
65407         DUK__MK_LBP(DUK__BP_MULTIPLICATIVE),                      /* DUK_TOK_MUL */
65408         DUK__MK_LBP(DUK__BP_MULTIPLICATIVE),                      /* DUK_TOK_DIV */
65409         DUK__MK_LBP(DUK__BP_MULTIPLICATIVE),                      /* DUK_TOK_MOD */
65410         DUK__MK_LBP(DUK__BP_EXPONENTIATION),                      /* DUK_TOK_EXP */
65411         DUK__MK_LBP(DUK__BP_POSTFIX),                             /* DUK_TOK_INCREMENT */
65412         DUK__MK_LBP(DUK__BP_POSTFIX),                             /* DUK_TOK_DECREMENT */
65413         DUK__MK_LBP(DUK__BP_SHIFT),                               /* DUK_TOK_ALSHIFT */
65414         DUK__MK_LBP(DUK__BP_SHIFT),                               /* DUK_TOK_ARSHIFT */
65415         DUK__MK_LBP(DUK__BP_SHIFT),                               /* DUK_TOK_RSHIFT */
65416         DUK__MK_LBP(DUK__BP_BAND),                                /* DUK_TOK_BAND */
65417         DUK__MK_LBP(DUK__BP_BOR),                                 /* DUK_TOK_BOR */
65418         DUK__MK_LBP(DUK__BP_BXOR),                                /* DUK_TOK_BXOR */
65419         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_LNOT */
65420         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_BNOT */
65421         DUK__MK_LBP(DUK__BP_LAND),                                /* DUK_TOK_LAND */
65422         DUK__MK_LBP(DUK__BP_LOR),                                 /* DUK_TOK_LOR */
65423         DUK__MK_LBP(DUK__BP_CONDITIONAL),                         /* DUK_TOK_QUESTION */
65424         DUK__MK_LBP(DUK__BP_INVALID),                             /* DUK_TOK_COLON */
65425         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_EQUALSIGN */
65426         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_ADD_EQ */
65427         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_SUB_EQ */
65428         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_MUL_EQ */
65429         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_DIV_EQ */
65430         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_MOD_EQ */
65431         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_EXP_EQ */
65432         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_ALSHIFT_EQ */
65433         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_ARSHIFT_EQ */
65434         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_RSHIFT_EQ */
65435         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_BAND_EQ */
65436         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_BOR_EQ */
65437         DUK__MK_LBP(DUK__BP_ASSIGNMENT),                          /* DUK_TOK_BXOR_EQ */
65438         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_NUMBER */
65439         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_STRING */
65440         DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP),  /* DUK_TOK_REGEXP */
65441 };
65442
65443 /*
65444  *  Misc helpers
65445  */
65446
65447 DUK_LOCAL void duk__comp_recursion_increase(duk_compiler_ctx *comp_ctx) {
65448         DUK_ASSERT(comp_ctx != NULL);
65449         DUK_ASSERT(comp_ctx->recursion_depth >= 0);
65450         if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
65451                 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT);
65452                 DUK_WO_NORETURN(return;);
65453         }
65454         comp_ctx->recursion_depth++;
65455 }
65456
65457 DUK_LOCAL void duk__comp_recursion_decrease(duk_compiler_ctx *comp_ctx) {
65458         DUK_ASSERT(comp_ctx != NULL);
65459         DUK_ASSERT(comp_ctx->recursion_depth > 0);
65460         comp_ctx->recursion_depth--;
65461 }
65462
65463 DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
65464         DUK_UNREF(comp_ctx);
65465         DUK_ASSERT(h != NULL);
65466         return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h);
65467 }
65468
65469 DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
65470         DUK_ASSERT(h != NULL);
65471         return (comp_ctx->curr_func.is_strict &&
65472                 DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h));
65473 }
65474
65475 /*
65476  *  Parser duk__advance() token eating functions
65477  */
65478
65479 /* XXX: valstack handling is awkward.  Add a valstack helper which
65480  * avoids dup():ing; valstack_copy(src, dst)?
65481  */
65482
65483 DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
65484         duk_hthread *thr = comp_ctx->thr;
65485         duk_bool_t regexp;
65486
65487         DUK_ASSERT_DISABLE(comp_ctx->curr_token.t >= 0);  /* unsigned */
65488         DUK_ASSERT(comp_ctx->curr_token.t <= DUK_TOK_MAXVAL);  /* MAXVAL is inclusive */
65489
65490         /*
65491          *  Use current token to decide whether a RegExp can follow.
65492          *
65493          *  We can use either 't' or 't_nores'; the latter would not
65494          *  recognize keywords.  Some keywords can be followed by a
65495          *  RegExp (e.g. "return"), so using 't' is better.  This is
65496          *  not trivial, see doc/compiler.rst.
65497          */
65498
65499         regexp = 1;
65500         if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) {
65501                 regexp = 0;
65502         }
65503         if (comp_ctx->curr_func.reject_regexp_in_adv) {
65504                 comp_ctx->curr_func.reject_regexp_in_adv = 0;
65505                 regexp = 0;
65506         }
65507         if (comp_ctx->curr_func.allow_regexp_in_adv) {
65508                 comp_ctx->curr_func.allow_regexp_in_adv = 0;
65509                 regexp = 1;
65510         }
65511
65512         if (expect >= 0 && comp_ctx->curr_token.t != (duk_small_uint_t) expect) {
65513                 DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
65514                                  (long) expect, (long) comp_ctx->curr_token.t));
65515                 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
65516                 DUK_WO_NORETURN(return;);
65517         }
65518
65519         /* make current token the previous; need to fiddle with valstack "backing store" */
65520         duk_memcpy(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
65521         duk_copy(thr, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
65522         duk_copy(thr, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
65523
65524         /* parse new token */
65525         duk_lexer_parse_js_input_element(&comp_ctx->lex,
65526                                          &comp_ctx->curr_token,
65527                                          comp_ctx->curr_func.is_strict,
65528                                          regexp);
65529
65530         DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T "
65531                              "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T",
65532                              (long) comp_ctx->curr_token.t,
65533                              (long) comp_ctx->curr_token.t_nores,
65534                              (long) comp_ctx->curr_token.start_line,
65535                              (long) comp_ctx->curr_token.lineterm,
65536                              (duk_tval *) duk_get_tval(thr, comp_ctx->tok11_idx),
65537                              (duk_tval *) duk_get_tval(thr, comp_ctx->tok12_idx),
65538                              (long) comp_ctx->prev_token.t,
65539                              (long) comp_ctx->prev_token.t_nores,
65540                              (long) comp_ctx->prev_token.start_line,
65541                              (long) comp_ctx->prev_token.lineterm,
65542                              (duk_tval *) duk_get_tval(thr, comp_ctx->tok21_idx),
65543                              (duk_tval *) duk_get_tval(thr, comp_ctx->tok22_idx)));
65544 }
65545
65546 /* advance, expecting current token to be a specific token; parse next token in regexp context */
65547 DUK_LOCAL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
65548         duk__advance_helper(comp_ctx, expect);
65549 }
65550
65551 /* advance, whatever the current token is; parse next token in regexp context */
65552 DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) {
65553         duk__advance_helper(comp_ctx, -1);
65554 }
65555
65556 /*
65557  *  Helpers for duk_compiler_func.
65558  */
65559
65560 /* init function state: inits valstack allocations */
65561 DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
65562         duk_compiler_func *func = &comp_ctx->curr_func;
65563         duk_hthread *thr = comp_ctx->thr;
65564         duk_idx_t entry_top;
65565
65566         entry_top = duk_get_top(thr);
65567
65568         duk_memzero(func, sizeof(*func));  /* intentional overlap with earlier memzero */
65569 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
65570         func->h_name = NULL;
65571         func->h_consts = NULL;
65572         func->h_funcs = NULL;
65573         func->h_decls = NULL;
65574         func->h_labelnames = NULL;
65575         func->h_labelinfos = NULL;
65576         func->h_argnames = NULL;
65577         func->h_varmap = NULL;
65578 #endif
65579
65580         duk_require_stack(thr, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
65581
65582         DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
65583         /* code_idx = entry_top + 0 */
65584
65585         duk_push_array(thr);
65586         func->consts_idx = entry_top + 1;
65587         func->h_consts = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 1);
65588         DUK_ASSERT(func->h_consts != NULL);
65589
65590         duk_push_array(thr);
65591         func->funcs_idx = entry_top + 2;
65592         func->h_funcs = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 2);
65593         DUK_ASSERT(func->h_funcs != NULL);
65594         DUK_ASSERT(func->fnum_next == 0);
65595
65596         duk_push_array(thr);
65597         func->decls_idx = entry_top + 3;
65598         func->h_decls = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 3);
65599         DUK_ASSERT(func->h_decls != NULL);
65600
65601         duk_push_array(thr);
65602         func->labelnames_idx = entry_top + 4;
65603         func->h_labelnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 4);
65604         DUK_ASSERT(func->h_labelnames != NULL);
65605
65606         duk_push_dynamic_buffer(thr, 0);
65607         func->labelinfos_idx = entry_top + 5;
65608         func->h_labelinfos = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 5);
65609         DUK_ASSERT(func->h_labelinfos != NULL);
65610         DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos));
65611
65612         duk_push_array(thr);
65613         func->argnames_idx = entry_top + 6;
65614         func->h_argnames = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 6);
65615         DUK_ASSERT(func->h_argnames != NULL);
65616
65617         duk_push_bare_object(thr);
65618         func->varmap_idx = entry_top + 7;
65619         func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, entry_top + 7);
65620         DUK_ASSERT(func->h_varmap != NULL);
65621 }
65622
65623 /* reset function state (prepare for pass 2) */
65624 DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
65625         duk_compiler_func *func = &comp_ctx->curr_func;
65626         duk_hthread *thr = comp_ctx->thr;
65627
65628         /* reset bytecode buffer but keep current size; pass 2 will
65629          * require same amount or more.
65630          */
65631         DUK_BW_RESET_SIZE(thr, &func->bw_code);
65632
65633         duk_set_length(thr, func->consts_idx, 0);
65634         /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
65635         func->fnum_next = 0;
65636         /* duk_set_length(thr, func->funcs_idx, 0); */
65637         duk_set_length(thr, func->labelnames_idx, 0);
65638         duk_hbuffer_reset(thr, func->h_labelinfos);
65639         /* keep func->h_argnames; it is fixed for all passes */
65640
65641         /* truncated in case pass 3 needed */
65642         duk_push_bare_object(thr);
65643         duk_replace(thr, func->varmap_idx);
65644         func->h_varmap = DUK_GET_HOBJECT_POSIDX(thr, func->varmap_idx);
65645         DUK_ASSERT(func->h_varmap != NULL);
65646 }
65647
65648 /* cleanup varmap from any null entries, compact it, etc; returns number
65649  * of final entries after cleanup.
65650  */
65651 DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
65652         duk_hthread *thr = comp_ctx->thr;
65653         duk_hobject *h_varmap;
65654         duk_hstring *h_key;
65655         duk_tval *tv;
65656         duk_uint32_t i, e_next;
65657         duk_int_t ret;
65658
65659         /* [ ... varmap ] */
65660
65661         h_varmap = DUK_GET_HOBJECT_NEGIDX(thr, -1);
65662         DUK_ASSERT(h_varmap != NULL);
65663
65664         ret = 0;
65665         e_next = DUK_HOBJECT_GET_ENEXT(h_varmap);
65666         for (i = 0; i < e_next; i++) {
65667                 h_key = DUK_HOBJECT_E_GET_KEY(thr->heap, h_varmap, i);
65668                 if (!h_key) {
65669                         continue;
65670                 }
65671
65672                 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i));
65673
65674                 /* The entries can either be register numbers or 'null' values.
65675                  * Thus, no need to DECREF them and get side effects.  DECREF'ing
65676                  * the keys (strings) can cause memory to be freed but no side
65677                  * effects as strings don't have finalizers.  This is why we can
65678                  * rely on the object properties not changing from underneath us.
65679                  */
65680
65681                 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h_varmap, i);
65682                 if (!DUK_TVAL_IS_NUMBER(tv)) {
65683                         DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv));
65684                         DUK_HOBJECT_E_SET_KEY(thr->heap, h_varmap, i, NULL);
65685                         DUK_HSTRING_DECREF(thr, h_key);
65686                         /* when key is NULL, value is garbage so no need to set */
65687                 } else {
65688                         ret++;
65689                 }
65690         }
65691
65692         duk_compact_m1(thr);
65693
65694         return ret;
65695 }
65696
65697 /* Convert duk_compiler_func into a function template, leaving the result
65698  * on top of stack.
65699  */
65700 /* XXX: awkward and bloated asm -- use faster internal accesses */
65701 DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
65702         duk_compiler_func *func = &comp_ctx->curr_func;
65703         duk_hthread *thr = comp_ctx->thr;
65704         duk_hcompfunc *h_res;
65705         duk_hbuffer_fixed *h_data;
65706         duk_size_t consts_count;
65707         duk_size_t funcs_count;
65708         duk_size_t code_count;
65709         duk_size_t code_size;
65710         duk_size_t data_size;
65711         duk_size_t i;
65712         duk_tval *p_const;
65713         duk_hobject **p_func;
65714         duk_instr_t *p_instr;
65715         duk_compiler_instr *q_instr;
65716         duk_tval *tv;
65717         duk_bool_t keep_varmap;
65718         duk_bool_t keep_formals;
65719 #if !defined(DUK_USE_DEBUGGER_SUPPORT)
65720         duk_size_t formals_length;
65721 #endif
65722
65723         DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
65724
65725         /*
65726          *  Push result object and init its flags
65727          */
65728
65729         /* Valstack should suffice here, required on function valstack init */
65730
65731         h_res = duk_push_hcompfunc(thr);
65732         DUK_ASSERT(h_res != NULL);
65733         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_res) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
65734         DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_res, NULL);  /* Function templates are "bare objects". */
65735
65736         if (func->is_function) {
65737                 DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
65738                 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
65739
65740                 if (!func->is_arguments_shadowed) {
65741                         /* arguments object would be accessible; note that shadowing
65742                          * bindings are arguments or function declarations, neither
65743                          * of which are deletable, so this is safe.
65744                          */
65745
65746                         if (func->id_access_arguments || func->may_direct_eval) {
65747                                 DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or "
65748                                                      "indirectly -> set CREATEARGS"));
65749                                 DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res);
65750                         }
65751                 }
65752         } else if (func->is_eval && func->is_strict) {
65753                 DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV"));
65754                 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
65755         } else {
65756                 /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
65757                  * global code: env is is global env
65758                  */
65759                 DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV"));
65760                 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res));
65761         }
65762
65763 #if defined(DUK_USE_FUNC_NAME_PROPERTY)
65764         if (func->is_function && func->is_namebinding && func->h_name != NULL) {
65765                 /* Object literal set/get functions have a name (property
65766                  * name) but must not have a lexical name binding, see
65767                  * test-bug-getset-func-name.js.
65768                  */
65769                 DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
65770                 DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
65771         }
65772 #endif
65773
65774         if (func->is_strict) {
65775                 DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
65776                 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
65777         }
65778
65779         if (func->is_notail) {
65780                 DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
65781                 DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
65782         }
65783
65784         if (func->is_constructable) {
65785                 DUK_DDD(DUK_DDDPRINT("function is constructable -> set CONSTRUCTABLE"));
65786                 DUK_HOBJECT_SET_CONSTRUCTABLE((duk_hobject *) h_res);
65787         }
65788
65789         /*
65790          *  Build function fixed size 'data' buffer, which contains bytecode,
65791          *  constants, and inner function references.
65792          *
65793          *  During the building phase 'data' is reachable but incomplete.
65794          *  Only incref's occur during building (no refzero or GC happens),
65795          *  so the building process is atomic.
65796          */
65797
65798         consts_count = duk_hobject_get_length(thr, func->h_consts);
65799         funcs_count = duk_hobject_get_length(thr, func->h_funcs) / 3;
65800         code_count = DUK_BW_GET_SIZE(thr, &func->bw_code) / sizeof(duk_compiler_instr);
65801         code_size = code_count * sizeof(duk_instr_t);
65802
65803         data_size = consts_count * sizeof(duk_tval) +
65804                     funcs_count * sizeof(duk_hobject *) +
65805                     code_size;
65806
65807         DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> "
65808                              "data_size=%ld*%ld + %ld*%ld + %ld = %ld",
65809                              (long) consts_count, (long) funcs_count, (long) code_size,
65810                              (long) consts_count, (long) sizeof(duk_tval),
65811                              (long) funcs_count, (long) sizeof(duk_hobject *),
65812                              (long) code_size, (long) data_size));
65813
65814         duk_push_fixed_buffer_nozero(thr, data_size);
65815         h_data = (duk_hbuffer_fixed *) (void *) duk_known_hbuffer(thr, -1);
65816
65817         DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
65818         DUK_HEAPHDR_INCREF(thr, h_data);
65819
65820         p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data);
65821         for (i = 0; i < consts_count; i++) {
65822                 DUK_ASSERT(i <= DUK_UARRIDX_MAX);  /* const limits */
65823                 tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_consts, (duk_uarridx_t) i);
65824                 DUK_ASSERT(tv != NULL);
65825                 DUK_TVAL_SET_TVAL(p_const, tv);
65826                 p_const++;
65827                 DUK_TVAL_INCREF(thr, tv);  /* may be a string constant */
65828
65829                 DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval *) tv));
65830         }
65831
65832         p_func = (duk_hobject **) p_const;
65833         DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_res, p_func);
65834         for (i = 0; i < funcs_count; i++) {
65835                 duk_hobject *h;
65836                 DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX);  /* func limits */
65837                 tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_funcs, (duk_uarridx_t) (i * 3));
65838                 DUK_ASSERT(tv != NULL);
65839                 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
65840                 h = DUK_TVAL_GET_OBJECT(tv);
65841                 DUK_ASSERT(h != NULL);
65842                 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(h));
65843                 *p_func++ = h;
65844                 DUK_HOBJECT_INCREF(thr, h);
65845
65846                 DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO",
65847                                      (void *) h, (duk_heaphdr *) h));
65848         }
65849
65850         p_instr = (duk_instr_t *) p_func;
65851         DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_res, p_instr);
65852
65853         /* copy bytecode instructions one at a time */
65854         q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code);
65855         for (i = 0; i < code_count; i++) {
65856                 p_instr[i] = q_instr[i].ins;
65857         }
65858         /* Note: 'q_instr' is still used below */
65859
65860         DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
65861
65862         duk_pop(thr);  /* 'data' (and everything in it) is reachable through h_res now */
65863
65864         /*
65865          *  Init non-property result fields
65866          *
65867          *  'nregs' controls how large a register frame is allocated.
65868          *
65869          *  'nargs' controls how many formal arguments are written to registers:
65870          *  r0, ... r(nargs-1).  The remaining registers are initialized to
65871          *  undefined.
65872          */
65873
65874         DUK_ASSERT(func->temp_max >= 0);
65875         h_res->nregs = (duk_uint16_t) func->temp_max;
65876         h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
65877         DUK_ASSERT(h_res->nregs >= h_res->nargs);  /* pass2 allocation handles this */
65878 #if defined(DUK_USE_DEBUGGER_SUPPORT)
65879         h_res->start_line = (duk_uint32_t) func->min_line;
65880         h_res->end_line = (duk_uint32_t) func->max_line;
65881 #endif
65882
65883         /*
65884          *  Init object properties
65885          *
65886          *  Properties should be added in decreasing order of access frequency.
65887          *  (Not very critical for function templates.)
65888          */
65889
65890         DUK_DDD(DUK_DDDPRINT("init function properties"));
65891
65892         /* [ ... res ] */
65893
65894         /* _Varmap: omitted if function is guaranteed not to do a slow path
65895          * identifier access that might be caught by locally declared variables.
65896          * The varmap can also be omitted if it turns out empty of actual
65897          * register mappings after a cleanup.  When debugging is enabled, we
65898          * always need the varmap to be able to lookup variables at any point.
65899          */
65900
65901 #if defined(DUK_USE_DEBUGGER_SUPPORT)
65902         DUK_DD(DUK_DDPRINT("keeping _Varmap because debugger support is enabled"));
65903         keep_varmap = 1;
65904 #else
65905         if (func->id_access_slow_own ||   /* directly uses slow accesses that may match own variables */
65906             func->id_access_arguments ||  /* accesses 'arguments' directly */
65907             func->may_direct_eval ||      /* may indirectly slow access through a direct eval */
65908             funcs_count > 0) {            /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
65909                 DUK_DD(DUK_DDPRINT("keeping _Varmap because of direct eval, slow path access that may match local variables, or presence of inner functions"));
65910                 keep_varmap = 1;
65911         } else {
65912                 DUK_DD(DUK_DDPRINT("dropping _Varmap"));
65913                 keep_varmap = 0;
65914         }
65915 #endif
65916
65917         if (keep_varmap) {
65918                 duk_int_t num_used;
65919                 duk_dup(thr, func->varmap_idx);
65920                 num_used = duk__cleanup_varmap(comp_ctx);
65921                 DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
65922                                      (duk_tval *) duk_get_tval(thr, -1), (long) num_used));
65923
65924                 if (num_used > 0) {
65925                         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
65926                 } else {
65927                         DUK_DD(DUK_DDPRINT("varmap is empty after cleanup -> no need to add"));
65928                         duk_pop(thr);
65929                 }
65930         }
65931
65932         /* _Formals: omitted if function is guaranteed not to need a (non-strict)
65933          * arguments object, and _Formals.length matches nargs exactly.
65934          *
65935          * Non-arrow functions can't see an outer function's 'argument' binding
65936          * (because they have their own), but arrow functions can.  When arrow
65937          * functions are added, this condition would need to be added:
65938          *     inner_arrow_funcs_count > 0   inner arrow functions may access 'arguments'
65939          */
65940 #if defined(DUK_USE_DEBUGGER_SUPPORT)
65941         DUK_DD(DUK_DDPRINT("keeping _Formals because debugger support is enabled"));
65942         keep_formals = 1;
65943 #else
65944         formals_length = duk_get_length(thr, func->argnames_idx);
65945         if (formals_length != (duk_size_t) h_res->nargs) {
65946                 /* Nargs not enough for closure .length: keep _Formals regardless
65947                  * of its length.  Shouldn't happen in practice at the moment.
65948                  */
65949                 DUK_DD(DUK_DDPRINT("keeping _Formals because _Formals.length != nargs"));
65950                 keep_formals = 1;
65951         } else if ((func->id_access_arguments || func->may_direct_eval) &&
65952                    (formals_length > 0)) {
65953                 /* Direct eval (may access 'arguments') or accesses 'arguments'
65954                  * explicitly: keep _Formals unless it is zero length.
65955                  */
65956                 DUK_DD(DUK_DDPRINT("keeping _Formals because of direct eval or explicit access to 'arguments', and _Formals.length != 0"));
65957                 keep_formals = 1;
65958         } else {
65959                 DUK_DD(DUK_DDPRINT("omitting _Formals, nargs matches _Formals.length, so no properties added"));
65960                 keep_formals = 0;
65961         }
65962 #endif
65963
65964         if (keep_formals) {
65965                 duk_dup(thr, func->argnames_idx);
65966                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
65967         }
65968
65969         /* name */
65970 #if defined(DUK_USE_FUNC_NAME_PROPERTY)
65971         if (func->h_name) {
65972                 duk_push_hstring(thr, func->h_name);
65973                 DUK_DD(DUK_DDPRINT("setting function template .name to %!T", duk_get_tval(thr, -1)));
65974                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
65975         }
65976 #endif  /* DUK_USE_FUNC_NAME_PROPERTY */
65977
65978         /* _Source */
65979 #if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
65980         if (0) {
65981                 /* XXX: Currently function source code is not stored, as it is not
65982                  * required by the standard.  Source code should not be stored by
65983                  * default (user should enable it explicitly), and the source should
65984                  * probably be compressed with a trivial text compressor; average
65985                  * compression of 20-30% is quite easy to achieve even with a trivial
65986                  * compressor (RLE + backwards lookup).
65987                  *
65988                  * Debugging needs source code to be useful: sometimes input code is
65989                  * not found in files as it may be generated and then eval()'d, given
65990                  * by dynamic C code, etc.
65991                  *
65992                  * Other issues:
65993                  *
65994                  *   - Need tokenizer indices for start and end to substring
65995                  *   - Always normalize function declaration part?
65996                  *   - If we keep _Formals, only need to store body
65997                  */
65998
65999                 /*
66000                  *  For global or eval code this is straightforward.  For functions
66001                  *  created with the Function constructor we only get the source for
66002                  *  the body and must manufacture the "function ..." part.
66003                  *
66004                  *  For instance, for constructed functions (v8):
66005                  *
66006                  *    > a = new Function("foo", "bar", "print(foo)");
66007                  *    [Function]
66008                  *    > a.toString()
66009                  *    'function anonymous(foo,bar) {\nprint(foo)\n}'
66010                  *
66011                  *  Similarly for e.g. getters (v8):
66012                  *
66013                  *    > x = { get a(foo,bar) { print(foo); } }
66014                  *    { a: [Getter] }
66015                  *    > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
66016                  *    'function a(foo,bar) { print(foo); }'
66017                  */
66018
66019 #if 0
66020                 duk_push_literal(thr, "XXX");
66021                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
66022 #endif
66023         }
66024 #endif  /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
66025
66026         /* _Pc2line */
66027 #if defined(DUK_USE_PC2LINE)
66028         if (1) {
66029                 /*
66030                  *  Size-optimized pc->line mapping.
66031                  */
66032
66033                 DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
66034                 duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count);  /* -> pushes fixed buffer */
66035                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
66036
66037                 /* XXX: if assertions enabled, walk through all valid PCs
66038                  * and check line mapping.
66039                  */
66040         }
66041 #endif  /* DUK_USE_PC2LINE */
66042
66043         /* fileName */
66044 #if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
66045         if (comp_ctx->h_filename) {
66046                 /*
66047                  *  Source filename (or equivalent), for identifying thrown errors.
66048                  */
66049
66050                 duk_push_hstring(thr, comp_ctx->h_filename);
66051                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
66052         }
66053 #endif
66054
66055         DUK_DD(DUK_DDPRINT("converted function: %!ixT",
66056                            (duk_tval *) duk_get_tval(thr, -1)));
66057
66058         /*
66059          *  Compact the function template.
66060          */
66061
66062         duk_compact_m1(thr);
66063
66064         /*
66065          *  Debug dumping
66066          */
66067
66068 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
66069         {
66070                 duk_hcompfunc *h;
66071                 duk_instr_t *p, *p_start, *p_end;
66072
66073                 h = (duk_hcompfunc *) duk_get_hobject(thr, -1);
66074                 p_start = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, h);
66075                 p_end = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, h);
66076
66077                 p = p_start;
66078                 while (p < p_end) {
66079                         DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I        ; 0x%08lx op=%ld (%!C) a=%ld b=%ld c=%ld",
66080                                              (long) (p - p_start),
66081                                              (duk_instr_t) (*p),
66082                                              (unsigned long) (*p),
66083                                              (long) DUK_DEC_OP(*p),
66084                                              (long) DUK_DEC_OP(*p),
66085                                              (long) DUK_DEC_A(*p),
66086                                              (long) DUK_DEC_B(*p),
66087                                              (long) DUK_DEC_C(*p)));
66088                         p++;
66089                 }
66090         }
66091 #endif
66092 }
66093
66094 /*
66095  *  Code emission helpers
66096  *
66097  *  Some emission helpers understand the range of target and source reg/const
66098  *  values and automatically emit shuffling code if necessary.  This is the
66099  *  case when the slot in question (A, B, C) is used in the standard way and
66100  *  for opcodes the emission helpers explicitly understand (like DUK_OP_MPUTOBJ).
66101  *
66102  *  The standard way is that:
66103  *    - slot A is a target register
66104  *    - slot B is a source register/constant
66105  *    - slot C is a source register/constant
66106  *
66107  *  If a slot is used in a non-standard way the caller must indicate this
66108  *  somehow.  If a slot is used as a target instead of a source (or vice
66109  *  versa), this can be indicated with a flag to trigger proper shuffling
66110  *  (e.g. DUK__EMIT_FLAG_B_IS_TARGET).  If the value in the slot is not
66111  *  register/const related at all, the caller must ensure that the raw value
66112  *  fits into the corresponding slot so as to not trigger shuffling.  The
66113  *  caller must set a "no shuffle" flag to ensure compilation fails if
66114  *  shuffling were to be triggered because of an internal error.
66115  *
66116  *  For slots B and C the raw slot size is 9 bits but one bit is reserved for
66117  *  the reg/const indicator.  To use the full 9-bit range for a raw value,
66118  *  shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag.
66119  *  Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots.
66120  *
66121  *  There is call handling specific understanding in the A-B-C emitter to
66122  *  convert call setup and call instructions into indirect ones if necessary.
66123  */
66124
66125 /* Code emission flags, passed in the 'opcode' field.  Opcode + flags
66126  * fit into 16 bits for now, so use duk_small_uint_t.
66127  */
66128 #define DUK__EMIT_FLAG_NO_SHUFFLE_A      (1 << 8)
66129 #define DUK__EMIT_FLAG_NO_SHUFFLE_B      (1 << 9)
66130 #define DUK__EMIT_FLAG_NO_SHUFFLE_C      (1 << 10)
66131 #define DUK__EMIT_FLAG_A_IS_SOURCE       (1 << 11)  /* slot A is a source (default: target) */
66132 #define DUK__EMIT_FLAG_B_IS_TARGET       (1 << 12)  /* slot B is a target (default: source) */
66133 #define DUK__EMIT_FLAG_C_IS_TARGET       (1 << 13)  /* slot C is a target (default: source) */
66134 #define DUK__EMIT_FLAG_BC_REGCONST       (1 << 14)  /* slots B and C are reg/const */
66135 #define DUK__EMIT_FLAG_RESERVE_JUMPSLOT  (1 << 15)  /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */
66136
66137 /* XXX: macro smaller than call? */
66138 DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) {
66139         duk_compiler_func *func;
66140         func = &comp_ctx->curr_func;
66141         return (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &func->bw_code) / sizeof(duk_compiler_instr));
66142 }
66143
66144 DUK_LOCAL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc) {
66145         DUK_ASSERT(pc >= 0);
66146         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)));
66147         return ((duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code)) + pc;
66148 }
66149
66150 /* emit instruction; could return PC but that's not needed in the majority
66151  * of cases.
66152  */
66153 DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
66154 #if defined(DUK_USE_PC2LINE)
66155         duk_int_t line;
66156 #endif
66157         duk_compiler_instr *instr;
66158
66159         DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I",
66160                              (unsigned long) ins,
66161                              (long) comp_ctx->curr_token.start_line,
66162                              (long) comp_ctx->prev_token.start_line,
66163                              (long) duk__get_current_pc(comp_ctx),
66164                              (duk_instr_t) ins));
66165
66166         instr = (duk_compiler_instr *) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
66167         DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
66168
66169 #if defined(DUK_USE_PC2LINE)
66170         /* The line number tracking is a bit inconsistent right now, which
66171          * affects debugger accuracy.  Mostly call sites emit opcodes when
66172          * they have parsed a token (say a terminating semicolon) and called
66173          * duk__advance().  In this case the line number of the previous
66174          * token is the most accurate one (except in prologue where
66175          * prev_token.start_line is 0).  This is probably not 100% correct
66176          * right now.
66177          */
66178         /* approximation, close enough */
66179         line = comp_ctx->prev_token.start_line;
66180         if (line == 0) {
66181                 line = comp_ctx->curr_token.start_line;
66182         }
66183 #endif
66184
66185         instr->ins = ins;
66186 #if defined(DUK_USE_PC2LINE)
66187         instr->line = (duk_uint32_t) line;
66188 #endif
66189 #if defined(DUK_USE_DEBUGGER_SUPPORT)
66190         if (line < comp_ctx->curr_func.min_line) {
66191                 comp_ctx->curr_func.min_line = line;
66192         }
66193         if (line > comp_ctx->curr_func.max_line) {
66194                 comp_ctx->curr_func.max_line = line;
66195         }
66196 #endif
66197
66198         /* Limit checks for bytecode byte size and line number. */
66199         if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
66200                 goto fail_bc_limit;
66201         }
66202 #if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS)
66203 #if defined(DUK_USE_BUFLEN16)
66204         /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */
66205         if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
66206                 goto fail_bc_limit;
66207         }
66208 #else
66209         if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
66210                 goto fail_bc_limit;
66211         }
66212 #endif
66213 #endif
66214
66215         return;
66216
66217   fail_bc_limit:
66218         DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
66219         DUK_WO_NORETURN(return;);
66220 }
66221
66222 /* Update function min/max line from current token.  Needed to improve
66223  * function line range information for debugging, so that e.g. opening
66224  * curly brace is covered by line range even when no opcodes are emitted
66225  * for the line containing the brace.
66226  */
66227 DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) {
66228 #if defined(DUK_USE_DEBUGGER_SUPPORT)
66229         duk_int_t line;
66230
66231         line = comp_ctx->curr_token.start_line;
66232         if (line == 0) {
66233                 return;
66234         }
66235         if (line < comp_ctx->curr_func.min_line) {
66236                 comp_ctx->curr_func.min_line = line;
66237         }
66238         if (line > comp_ctx->curr_func.max_line) {
66239                 comp_ctx->curr_func.max_line = line;
66240         }
66241 #else
66242         DUK_UNREF(comp_ctx);
66243 #endif
66244 }
66245
66246 DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) {
66247         duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0));
66248 }
66249
66250 /* Important main primitive. */
66251 DUK_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) {
66252         duk_instr_t ins = 0;
66253         duk_int_t a_out = -1;
66254         duk_int_t b_out = -1;
66255         duk_int_t c_out = -1;
66256         duk_int_t tmp;
66257         duk_small_uint_t op = op_flags & 0xffU;
66258
66259         DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
66260                              (unsigned long) op_flags, (long) a, (long) b, (long) c));
66261
66262         /* We could rely on max temp/const checks: if they don't exceed BC
66263          * limit, nothing here can either (just asserts would be enough).
66264          * Currently we check for the limits, which provides additional
66265          * protection against creating invalid bytecode due to compiler
66266          * bugs.
66267          */
66268
66269         DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN);  /* unsigned */
66270         DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
66271         DUK_ASSERT(DUK__ISREG(a));
66272         DUK_ASSERT(b != -1);  /* Not 'none'. */
66273         DUK_ASSERT(c != -1);  /* Not 'none'. */
66274
66275         /* Input shuffling happens before the actual operation, while output
66276          * shuffling happens afterwards.  Output shuffling decisions are still
66277          * made at the same time to reduce branch clutter; output shuffle decisions
66278          * are recorded into X_out variables.
66279          */
66280
66281         /* Slot A: currently no support for reg/const. */
66282
66283 #if defined(DUK_USE_SHUFFLE_TORTURE)
66284         if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
66285 #else
66286         if (a <= DUK_BC_A_MAX) {
66287 #endif
66288                 ;
66289         } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
66290                 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a));
66291                 goto error_outofregs;
66292         } else if (a <= DUK_BC_BC_MAX) {
66293                 comp_ctx->curr_func.needs_shuffle = 1;
66294                 tmp = comp_ctx->curr_func.shuffle1;
66295                 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
66296                         duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
66297                 } else {
66298                         /* Output shuffle needed after main operation */
66299                         a_out = a;
66300
66301                         /* The DUK_OP_CSVAR output shuffle assumes shuffle registers are
66302                          * consecutive.
66303                          */
66304                         DUK_ASSERT((comp_ctx->curr_func.shuffle1 == 0 && comp_ctx->curr_func.shuffle2 == 0) ||
66305                                    (comp_ctx->curr_func.shuffle2 == comp_ctx->curr_func.shuffle1 + 1));
66306                         if (op == DUK_OP_CSVAR) {
66307                                 /* For CSVAR the limit is one smaller because output shuffle
66308                                  * must be able to express 'a + 1' in BC.
66309                                  */
66310                                 if (a + 1 > DUK_BC_BC_MAX) {
66311                                         goto error_outofregs;
66312                                 }
66313                         }
66314                 }
66315                 a = tmp;
66316         } else {
66317                 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld", (long) a));
66318                 goto error_outofregs;
66319         }
66320
66321         /* Slot B: reg/const support, mapped to bit 0 of opcode. */
66322
66323         if ((b & DUK__CONST_MARKER) != 0) {
66324                 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
66325                 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
66326                 b = b & ~DUK__CONST_MARKER;
66327 #if defined(DUK_USE_SHUFFLE_TORTURE)
66328                 if (0) {
66329 #else
66330                 if (b <= 0xff) {
66331 #endif
66332                         if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) {
66333                                 /* Opcode follows B/C reg/const convention. */
66334                                 DUK_ASSERT((op & 0x01) == 0);
66335                                 ins |= DUK_ENC_OP_A_B_C(0x01, 0, 0, 0);  /* const flag for B */
66336                         } else {
66337                                 DUK_D(DUK_DPRINT("B is const, opcode is not B/C reg/const: %x", op_flags));
66338                         }
66339                 } else if (b <= DUK_BC_BC_MAX) {
66340                         comp_ctx->curr_func.needs_shuffle = 1;
66341                         tmp = comp_ctx->curr_func.shuffle2;
66342                         duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b));
66343                         b = tmp;
66344                 } else {
66345                         DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld", (long) b));
66346                         goto error_outofregs;
66347                 }
66348         } else {
66349 #if defined(DUK_USE_SHUFFLE_TORTURE)
66350                 if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) {
66351 #else
66352                 if (b <= 0xff) {
66353 #endif
66354                         ;
66355                 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) {
66356                         if (b > DUK_BC_B_MAX) {
66357                                 /* Note: 0xff != DUK_BC_B_MAX */
66358                                 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld", (long) b));
66359                                 goto error_outofregs;
66360                         }
66361                 } else if (b <= DUK_BC_BC_MAX) {
66362                         comp_ctx->curr_func.needs_shuffle = 1;
66363                         tmp = comp_ctx->curr_func.shuffle2;
66364                         if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) {
66365                                 /* Output shuffle needed after main operation */
66366                                 b_out = b;
66367                         }
66368                         if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET)) {
66369                                 if (op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
66370                                         /* Special handling for MPUTOBJ/MPUTARR shuffling.
66371                                          * For each, slot B identifies the first register of a range
66372                                          * of registers, so normal shuffling won't work.  Instead,
66373                                          * an indirect version of the opcode is used.
66374                                          */
66375                                         DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
66376                                         duk__emit_load_int32_noshuffle(comp_ctx, tmp, b);
66377                                         DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
66378                                         DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1);
66379                                         op_flags++;  /* indirect opcode follows direct */
66380                                 } else {
66381                                         duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b));
66382                                 }
66383                         }
66384                         b = tmp;
66385                 } else {
66386                         DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld", (long) b));
66387                         goto error_outofregs;
66388                 }
66389         }
66390
66391         /* Slot C: reg/const support, mapped to bit 1 of opcode. */
66392
66393         if ((c & DUK__CONST_MARKER) != 0) {
66394                 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
66395                 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
66396                 c = c & ~DUK__CONST_MARKER;
66397 #if defined(DUK_USE_SHUFFLE_TORTURE)
66398                 if (0) {
66399 #else
66400                 if (c <= 0xff) {
66401 #endif
66402                         if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) {
66403                                 /* Opcode follows B/C reg/const convention. */
66404                                 DUK_ASSERT((op & 0x02) == 0);
66405                                 ins |= DUK_ENC_OP_A_B_C(0x02, 0, 0, 0);  /* const flag for C */
66406                         } else {
66407                                 DUK_D(DUK_DPRINT("C is const, opcode is not B/C reg/const: %x", op_flags));
66408                         }
66409                 } else if (c <= DUK_BC_BC_MAX) {
66410                         comp_ctx->curr_func.needs_shuffle = 1;
66411                         tmp = comp_ctx->curr_func.shuffle3;
66412                         duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c));
66413                         c = tmp;
66414                 } else {
66415                         DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld", (long) c));
66416                         goto error_outofregs;
66417                 }
66418         } else {
66419 #if defined(DUK_USE_SHUFFLE_TORTURE)
66420                 if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) {
66421 #else
66422                 if (c <= 0xff) {
66423 #endif
66424                         ;
66425                 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) {
66426                         if (c > DUK_BC_C_MAX) {
66427                                 /* Note: 0xff != DUK_BC_C_MAX */
66428                                 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld", (long) c));
66429                                 goto error_outofregs;
66430                         }
66431                 } else if (c <= DUK_BC_BC_MAX) {
66432                         comp_ctx->curr_func.needs_shuffle = 1;
66433                         tmp = comp_ctx->curr_func.shuffle3;
66434                         if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) {
66435                                 /* Output shuffle needed after main operation */
66436                                 c_out = c;
66437                         } else {
66438                                 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
66439                         }
66440                         c = tmp;
66441                 } else {
66442                         DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld", (long) c));
66443                         goto error_outofregs;
66444                 }
66445         }
66446
66447         /* Main operation */
66448
66449         DUK_ASSERT(a >= DUK_BC_A_MIN);
66450         DUK_ASSERT(a <= DUK_BC_A_MAX);
66451         DUK_ASSERT(b >= DUK_BC_B_MIN);
66452         DUK_ASSERT(b <= DUK_BC_B_MAX);
66453         DUK_ASSERT(c >= DUK_BC_C_MIN);
66454         DUK_ASSERT(c <= DUK_BC_C_MAX);
66455
66456         ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
66457         duk__emit(comp_ctx, ins);
66458
66459         /* NEXTENUM needs a jump slot right after the main instruction.
66460          * When the JUMP is taken, output spilling is not needed so this
66461          * workaround is possible.  The jump slot PC is exceptionally
66462          * plumbed through comp_ctx to minimize call sites.
66463          */
66464         if (op_flags & DUK__EMIT_FLAG_RESERVE_JUMPSLOT) {
66465                 comp_ctx->emit_jumpslot_pc = duk__get_current_pc(comp_ctx);
66466                 duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
66467         }
66468
66469         /* Output shuffling: only one output register is realistically possible.
66470          *
66471          * (Zero would normally be an OK marker value: if the target register
66472          * was zero, it would never be shuffled.  But with DUK_USE_SHUFFLE_TORTURE
66473          * this is no longer true, so use -1 as a marker instead.)
66474          */
66475
66476         if (a_out >= 0) {
66477                 DUK_ASSERT(b_out < 0);
66478                 DUK_ASSERT(c_out < 0);
66479                 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
66480
66481                 if (op == DUK_OP_CSVAR) {
66482                         /* Special handling for CSVAR shuffling.  The variable lookup
66483                          * results in a <value, this binding> pair in successive
66484                          * registers so use two shuffle registers and two output
66485                          * loads.  (In practice this is dead code because temp/const
66486                          * limit is reached first.)
66487                          */
66488                         duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a + 1, a_out + 1));
66489                 }
66490         } else if (b_out >= 0) {
66491                 DUK_ASSERT(a_out < 0);
66492                 DUK_ASSERT(c_out < 0);
66493                 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out));
66494         } else if (c_out >= 0) {
66495                 DUK_ASSERT(b_out < 0);
66496                 DUK_ASSERT(c_out < 0);
66497                 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out));
66498         }
66499
66500         return;
66501
66502  error_outofregs:
66503         DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
66504         DUK_WO_NORETURN(return;);
66505 }
66506
66507 /* For many of the helpers below it'd be technically correct to add
66508  * "no shuffle" flags for parameters passed in as zero.  For example,
66509  * duk__emit_a_b() should call duk__emit_a_b_c() with C set to 0, and
66510  * DUK__EMIT_FLAG_NO_SHUFFLE_C added to op_flags.  However, since the
66511  * C value is 0, it'll never get shuffled so adding the flag is just
66512  * unnecessary additional code.  This is unfortunately not true for
66513  * "shuffle torture" mode which needs special handling.
66514  */
66515
66516 DUK_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) {
66517 #if defined(DUK_USE_SHUFFLE_TORTURE)
66518         op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_C;
66519 #endif
66520         duk__emit_a_b_c(comp_ctx, op_flags, a, b, 0);
66521 }
66522
66523 DUK_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) {
66524 #if defined(DUK_USE_SHUFFLE_TORTURE)
66525         op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A;
66526 #endif
66527         duk__emit_a_b_c(comp_ctx, op_flags, 0, b, c);
66528 }
66529
66530 #if 0  /* unused */
66531 DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
66532 #if defined(DUK_USE_SHUFFLE_TORTURE)
66533         op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C;
66534 #endif
66535         duk__emit_a_b_c(comp_ctx, op_flags, a, 0, 0);
66536 }
66537 #endif
66538
66539 #if 0  /* unused */
66540 DUK_LOCAL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b) {
66541 #if defined(DUK_USE_SHUFFLE_TORTURE)
66542         op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C;
66543 #endif
66544         duk__emit_a_b_c(comp_ctx, op_flags, 0, b, 0);
66545 }
66546 #endif
66547
66548 DUK_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) {
66549         duk_instr_t ins;
66550         duk_int_t tmp;
66551
66552         /* allow caller to give a const number with the DUK__CONST_MARKER */
66553         DUK_ASSERT(bc != -1);  /* Not 'none'. */
66554         bc = bc & (~DUK__CONST_MARKER);
66555
66556         DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN);  /* unsigned */
66557         DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
66558         DUK_ASSERT(bc >= DUK_BC_BC_MIN);
66559         DUK_ASSERT(bc <= DUK_BC_BC_MAX);
66560         DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
66561
66562         if (bc <= DUK_BC_BC_MAX) {
66563                 ;
66564         } else {
66565                 /* No BC shuffling now. */
66566                 goto error_outofregs;
66567         }
66568
66569 #if defined(DUK_USE_SHUFFLE_TORTURE)
66570         if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
66571 #else
66572         if (a <= DUK_BC_A_MAX) {
66573 #endif
66574                 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc);
66575                 duk__emit(comp_ctx, ins);
66576         } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
66577                 goto error_outofregs;
66578         } else if ((op_flags & 0xf0U) == DUK_OP_CALL0) {
66579                 comp_ctx->curr_func.needs_shuffle = 1;
66580                 tmp = comp_ctx->curr_func.shuffle1;
66581                 duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
66582                 op_flags |= DUK_BC_CALL_FLAG_INDIRECT;
66583                 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
66584                 duk__emit(comp_ctx, ins);
66585         } else if (a <= DUK_BC_BC_MAX) {
66586                 comp_ctx->curr_func.needs_shuffle = 1;
66587                 tmp = comp_ctx->curr_func.shuffle1;
66588                 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
66589                 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
66590                         duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
66591                         duk__emit(comp_ctx, ins);
66592                 } else {
66593                         duk__emit(comp_ctx, ins);
66594                         duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a));
66595                 }
66596         } else {
66597                 goto error_outofregs;
66598         }
66599         return;
66600
66601  error_outofregs:
66602         DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
66603         DUK_WO_NORETURN(return;);
66604 }
66605
66606 DUK_LOCAL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc) {
66607 #if defined(DUK_USE_SHUFFLE_TORTURE)
66608         op |= DUK__EMIT_FLAG_NO_SHUFFLE_A;
66609 #endif
66610         duk__emit_a_bc(comp_ctx, op, 0, bc);
66611 }
66612
66613 DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) {
66614         duk_instr_t ins;
66615
66616         DUK_ASSERT_DISABLE(op >= DUK_BC_OP_MIN);  /* unsigned */
66617         DUK_ASSERT(op <= DUK_BC_OP_MAX);
66618         DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN);  /* unsigned */
66619         DUK_ASSERT(abc <= DUK_BC_ABC_MAX);
66620         DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
66621         DUK_ASSERT(abc != -1);  /* Not 'none'. */
66622
66623         if (abc <= DUK_BC_ABC_MAX) {
66624                 ;
66625         } else {
66626                 goto error_outofregs;
66627         }
66628         ins = DUK_ENC_OP_ABC(op, abc);
66629         DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!C) abc=%ld (%!I)",
66630                              (unsigned long) ins, (long) comp_ctx->curr_token.start_line,
66631                              (long) duk__get_current_pc(comp_ctx), (long) op, (long) op,
66632                              (long) abc, (duk_instr_t) ins));
66633         duk__emit(comp_ctx, ins);
66634         return;
66635
66636  error_outofregs:
66637         DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
66638         DUK_WO_NORETURN(return;);
66639 }
66640
66641 DUK_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) {
66642         /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
66643          * would only shuffle once (instead of twice).  The current code works
66644          * though, and has a smaller compiler footprint.
66645          */
66646
66647         if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) &&
66648             (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) {
66649                 DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg, (long) val));
66650                 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS));
66651         } else {
66652                 duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT;
66653                 duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1);
66654                 DUK_ASSERT(lo >= 0);
66655                 DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld",
66656                                      (long) reg, (long) val, (long) hi, (long) lo));
66657                 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS));
66658                 duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo);
66659         }
66660 }
66661
66662 DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
66663         duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
66664 }
66665
66666 #if defined(DUK_USE_SHUFFLE_TORTURE)
66667 /* Used by duk__emit*() calls so that we don't shuffle the loadints that
66668  * are needed to handle indirect opcodes.
66669  */
66670 DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
66671         duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
66672 }
66673 #else
66674 DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_regconst_t reg, duk_int32_t val) {
66675         /* When torture not enabled, can just use the same helper because
66676          * 'reg' won't get spilled.
66677          */
66678         DUK_ASSERT(reg <= DUK_BC_A_MAX);
66679         duk__emit_load_int32(comp_ctx, reg, val);
66680 }
66681 #endif
66682
66683 DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) {
66684         duk_int_t curr_pc;
66685         duk_int_t offset;
66686
66687         curr_pc = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
66688         offset = (duk_int_t) target_pc - (duk_int_t) curr_pc - 1;
66689         DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN);
66690         DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX);
66691         duk__emit_abc(comp_ctx, DUK_OP_JUMP, (duk_regconst_t) (offset + DUK_BC_JUMP_BIAS));
66692 }
66693
66694 DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
66695         duk_int_t ret;
66696
66697         ret = duk__get_current_pc(comp_ctx);  /* useful for patching jumps later */
66698         duk__emit_op_only(comp_ctx, DUK_OP_JUMP);
66699         return ret;
66700 }
66701
66702 /* Insert an empty jump in the middle of code emitted earlier.  This is
66703  * currently needed for compiling for-in.
66704  */
66705 DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
66706 #if defined(DUK_USE_PC2LINE)
66707         duk_int_t line;
66708 #endif
66709         duk_compiler_instr *instr;
66710         duk_size_t offset;
66711
66712         DUK_ASSERT(jump_pc >= 0);
66713         offset = (duk_size_t) jump_pc * sizeof(duk_compiler_instr);
66714         instr = (duk_compiler_instr *) (void *)
66715                 DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr,
66716                                           &comp_ctx->curr_func.bw_code,
66717                                           offset,
66718                                           sizeof(duk_compiler_instr));
66719
66720 #if defined(DUK_USE_PC2LINE)
66721         line = comp_ctx->curr_token.start_line;  /* approximation, close enough */
66722 #endif
66723         instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
66724 #if defined(DUK_USE_PC2LINE)
66725         instr->line = (duk_uint32_t) line;
66726 #endif
66727
66728         DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
66729         if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
66730                 goto fail_bc_limit;
66731         }
66732         return;
66733
66734   fail_bc_limit:
66735         DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
66736         DUK_WO_NORETURN(return;);
66737 }
66738
66739 /* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
66740  * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this).
66741  */
66742 DUK_LOCAL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc) {
66743         duk_compiler_instr *instr;
66744         duk_int_t offset;
66745
66746         /* allow negative PCs, behave as a no-op */
66747         if (jump_pc < 0) {
66748                 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld",
66749                                      (long) jump_pc, (long) target_pc));
66750                 return;
66751         }
66752         DUK_ASSERT(jump_pc >= 0);
66753
66754         /* XXX: range assert */
66755         instr = duk__get_instr_ptr(comp_ctx, jump_pc);
66756         DUK_ASSERT(instr != NULL);
66757
66758         /* XXX: range assert */
66759         offset = target_pc - jump_pc - 1;
66760
66761         instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS);
66762         DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld",
66763                              (long) jump_pc, (long) target_pc, (long) offset));
66764 }
66765
66766 DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
66767         duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx));
66768 }
66769
66770 DUK_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) {
66771         duk_compiler_instr *instr;
66772
66773         DUK_ASSERT(DUK__ISREG(reg_catch));
66774
66775         instr = duk__get_instr_ptr(comp_ctx, ldconst_pc);
66776         DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST);
66777         DUK_ASSERT(instr != NULL);
66778         if (const_varname & DUK__CONST_MARKER) {
66779                 /* Have a catch variable. */
66780                 const_varname = const_varname & (~DUK__CONST_MARKER);
66781                 if (reg_catch > DUK_BC_BC_MAX || const_varname > DUK_BC_BC_MAX) {
66782                         /* Catch attempts to use out-of-range reg/const.  Without this
66783                          * check Duktape 0.12.0 could generate invalid code which caused
66784                          * an assert failure on execution.  This error is triggered e.g.
66785                          * for functions with a lot of constants and a try-catch statement.
66786                          * Shuffling or opcode semantics change is needed to fix the issue.
66787                          * See: test-bug-trycatch-many-constants.js.
66788                          */
66789                         DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)",
66790                                          (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname));
66791                         DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
66792                         DUK_WO_NORETURN(return;);
66793                 }
66794                 instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname);
66795         } else {
66796                 /* No catch variable, e.g. a try-finally; replace LDCONST with
66797                  * NOP to avoid a bogus LDCONST.
66798                  */
66799                 instr->ins = DUK_ENC_OP(DUK_OP_NOP);
66800         }
66801
66802         instr = duk__get_instr_ptr(comp_ctx, trycatch_pc);
66803         DUK_ASSERT(instr != NULL);
66804         DUK_ASSERT_DISABLE(flags >= DUK_BC_A_MIN);
66805         DUK_ASSERT(flags <= DUK_BC_A_MAX);
66806         instr->ins = DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH, flags, reg_catch);
66807 }
66808
66809 DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
66810         duk_small_uint_t op;
66811
66812         op = DUK__ISREG(regconst) ? DUK_OP_IFFALSE_R : DUK_OP_IFFALSE_C;
66813         duk__emit_bc(comp_ctx, op, regconst);  /* helper will remove const flag */
66814 }
66815
66816 DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
66817         duk_small_uint_t op;
66818
66819         op = DUK__ISREG(regconst) ? DUK_OP_IFTRUE_R : DUK_OP_IFTRUE_C;
66820         duk__emit_bc(comp_ctx, op, regconst);  /* helper will remove const flag */
66821 }
66822
66823 DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
66824         duk__emit_op_only(comp_ctx, DUK_OP_INVALID);
66825 }
66826
66827 /*
66828  *  Peephole optimizer for finished bytecode.
66829  *
66830  *  Does not remove opcodes; currently only straightens out unconditional
66831  *  jump chains which are generated by several control structures.
66832  */
66833
66834 DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
66835         duk_compiler_instr *bc;
66836         duk_small_uint_t iter;
66837         duk_int_t i, n;
66838         duk_int_t count_opt;
66839
66840         bc = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code);
66841 #if defined(DUK_USE_BUFLEN16)
66842         /* No need to assert, buffer size maximum is 0xffff. */
66843 #else
66844         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 */
66845 #endif
66846         n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
66847
66848         for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) {
66849                 count_opt = 0;
66850
66851                 for (i = 0; i < n; i++) {
66852                         duk_instr_t ins;
66853                         duk_int_t target_pc1;
66854                         duk_int_t target_pc2;
66855
66856                         ins = bc[i].ins;
66857                         if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
66858                                 continue;
66859                         }
66860
66861                         target_pc1 = i + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS;
66862                         DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1));
66863                         DUK_ASSERT(target_pc1 >= 0);
66864                         DUK_ASSERT(target_pc1 < n);
66865
66866                         /* Note: if target_pc1 == i, we'll optimize a jump to itself.
66867                          * This does not need to be checked for explicitly; the case
66868                          * is rare and max iter breaks us out.
66869                          */
66870
66871                         ins = bc[target_pc1].ins;
66872                         if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
66873                                 continue;
66874                         }
66875
66876                         target_pc2 = target_pc1 + 1 + (duk_int_t) DUK_DEC_ABC(ins) - (duk_int_t) DUK_BC_JUMP_BIAS;
66877
66878                         DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
66879                                              (long) i, (long) target_pc1, (long) target_pc2));
66880
66881                         bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS);
66882
66883                         count_opt++;
66884                 }
66885
66886                 DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt, (long) (iter + 1)));
66887
66888                 if (count_opt == 0) {
66889                         break;
66890                 }
66891         }
66892 }
66893
66894 /*
66895  *  Intermediate value helpers
66896  */
66897
66898 /* Flags for intermediate value coercions.  A flag for using a forced reg
66899  * is not needed, the forced_reg argument suffices and generates better
66900  * code (it is checked as it is used).
66901  */
66902 /* XXX: DUK__IVAL_FLAG_REQUIRE_SHORT is passed but not currently implemented
66903  * by ispec/ivalue operations.
66904  */
66905 #define DUK__IVAL_FLAG_ALLOW_CONST          (1 << 0)  /* allow a constant to be returned */
66906 #define DUK__IVAL_FLAG_REQUIRE_TEMP         (1 << 1)  /* require a (mutable) temporary as a result (or a const if allowed) */
66907 #define DUK__IVAL_FLAG_REQUIRE_SHORT        (1 << 2)  /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
66908
66909 /* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(thr,x) */
66910
66911 #if 0  /* enable manually for dumping */
66912 #define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
66913 #define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0)
66914
66915 DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) {
66916         DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
66917                          (long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx,
66918                          duk_get_tval(comp_ctx->thr, x->valstack_idx)));
66919 }
66920 DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
66921         DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
66922                          "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} "
66923                          "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
66924                          (long) x->t, (long) x->op,
66925                          (long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx,
66926                          duk_get_tval(comp_ctx->thr, x->x1.valstack_idx),
66927                          (long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx,
66928                          duk_get_tval(comp_ctx->thr, x->x2.valstack_idx)));
66929 }
66930 #else
66931 #define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
66932 #define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
66933 #endif
66934
66935 DUK_LOCAL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst) {
66936         x->t = DUK_IVAL_PLAIN;
66937         x->x1.t = DUK_ISPEC_REGCONST;
66938         x->x1.regconst = regconst;
66939 }
66940
66941 DUK_LOCAL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
66942         x->t = DUK_IVAL_PLAIN;
66943         x->x1.t = DUK_ISPEC_VALUE;
66944         duk_replace(comp_ctx->thr, x->x1.valstack_idx);
66945 }
66946
66947 DUK_LOCAL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
66948         x->t = DUK_IVAL_VAR;
66949         x->x1.t = DUK_ISPEC_VALUE;
66950         duk_replace(comp_ctx->thr, x->x1.valstack_idx);
66951 }
66952
66953 DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h) {
66954         DUK_ASSERT(h != NULL);
66955         duk_push_hstring(comp_ctx->thr, h);
66956         duk__ivalue_var_fromstack(comp_ctx, x);
66957 }
66958
66959 DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
66960         dst->t = src->t;
66961         dst->regconst = src->regconst;
66962         duk_copy(comp_ctx->thr, src->valstack_idx, dst->valstack_idx);
66963 }
66964
66965 DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
66966         dst->t = src->t;
66967         dst->op = src->op;
66968         dst->x1.t = src->x1.t;
66969         dst->x1.regconst = src->x1.regconst;
66970         dst->x2.t = src->x2.t;
66971         dst->x2.regconst = src->x2.regconst;
66972         duk_copy(comp_ctx->thr, src->x1.valstack_idx, dst->x1.valstack_idx);
66973         duk_copy(comp_ctx->thr, src->x2.valstack_idx, dst->x2.valstack_idx);
66974 }
66975
66976 DUK_LOCAL duk_regconst_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
66977         duk_regconst_t res;
66978
66979         res = comp_ctx->curr_func.temp_next;
66980         comp_ctx->curr_func.temp_next += num;
66981
66982         if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) {  /* == DUK__MAX_TEMPS is OK */
66983                 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT);
66984                 DUK_WO_NORETURN(return 0;);
66985         }
66986
66987         /* maintain highest 'used' temporary, needed to figure out nregs of function */
66988         if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) {
66989                 comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next;
66990         }
66991
66992         return res;
66993 }
66994
66995 DUK_LOCAL duk_regconst_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
66996         return duk__alloctemps(comp_ctx, 1);
66997 }
66998
66999 DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_regconst_t temp_next) {
67000         comp_ctx->curr_func.temp_next = temp_next;
67001         if (temp_next > comp_ctx->curr_func.temp_max) {
67002                 comp_ctx->curr_func.temp_max = temp_next;
67003         }
67004 }
67005
67006 /* get const for value at valstack top */
67007 DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
67008         duk_hthread *thr = comp_ctx->thr;
67009         duk_compiler_func *f = &comp_ctx->curr_func;
67010         duk_tval *tv1;
67011         duk_int_t i, n, n_check;
67012
67013         n = (duk_int_t) duk_get_length(thr, f->consts_idx);
67014
67015         tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
67016         DUK_ASSERT(tv1 != NULL);
67017
67018 #if defined(DUK_USE_FASTINT)
67019         /* Explicit check for fastint downgrade. */
67020         DUK_TVAL_CHKFAST_INPLACE_SLOW(tv1);
67021 #endif
67022
67023         /* Sanity workaround for handling functions with a large number of
67024          * constants at least somewhat reasonably.  Otherwise checking whether
67025          * we already have the constant would grow very slow (as it is O(N^2)).
67026          */
67027         n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n);
67028         for (i = 0; i < n_check; i++) {
67029                 duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, f->h_consts, i);
67030
67031                 /* Strict equality is NOT enough, because we cannot use the same
67032                  * constant for e.g. +0 and -0.
67033                  */
67034                 if (duk_js_samevalue(tv1, tv2)) {
67035                         DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
67036                                              (duk_tval *) tv1, (long) i));
67037                         duk_pop(thr);
67038                         return (duk_regconst_t) i | (duk_regconst_t) DUK__CONST_MARKER;
67039                 }
67040         }
67041
67042         if (n > DUK__MAX_CONSTS) {
67043                 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT);
67044                 DUK_WO_NORETURN(return 0;);
67045         }
67046
67047         DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
67048                              (duk_tval *) tv1, (long) n));
67049         (void) duk_put_prop_index(thr, f->consts_idx, (duk_uarridx_t) n);  /* invalidates tv1, tv2 */
67050         return (duk_regconst_t) n | (duk_regconst_t) DUK__CONST_MARKER;
67051 }
67052
67053 DUK_LOCAL duk_bool_t duk__const_needs_refcount(duk_compiler_ctx *comp_ctx, duk_regconst_t rc) {
67054 #if defined(DUK_USE_REFERENCE_COUNTING)
67055         duk_compiler_func *f = &comp_ctx->curr_func;
67056         duk_bool_t ret;
67057
67058         DUK_ASSERT((rc & DUK__CONST_MARKER) == 0);  /* caller removes const marker */
67059         (void) duk_get_prop_index(comp_ctx->thr, f->consts_idx, (duk_uarridx_t) rc);
67060         ret = !duk_is_number(comp_ctx->thr, -1);  /* now only number/string, so conservative check */
67061         duk_pop(comp_ctx->thr);
67062         return ret;
67063 #else
67064         DUK_UNREF(comp_ctx);
67065         DUK_UNREF(rc);
67066         DUK_ASSERT((rc & DUK__CONST_MARKER) == 0);  /* caller removes const marker */
67067         return 0;
67068 #endif
67069 }
67070
67071 /* Get the value represented by an duk_ispec to a register or constant.
67072  * The caller can control the result by indicating whether or not:
67073  *
67074  *   (1) a constant is allowed (sometimes the caller needs the result to
67075  *       be in a register)
67076  *
67077  *   (2) a temporary register is required (usually when caller requires
67078  *       the register to be safely mutable; normally either a bound
67079  *       register or a temporary register are both OK)
67080  *
67081  *   (3) a forced register target needs to be used
67082  *
67083  * Bytecode may be emitted to generate the necessary value.  The return
67084  * value is either a register or a constant.
67085  */
67086
67087 DUK_LOCAL
67088 duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
67089                                          duk_ispec *x,
67090                                          duk_regconst_t forced_reg,
67091                                          duk_small_uint_t flags) {
67092         duk_hthread *thr = comp_ctx->thr;
67093
67094         DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
67095                              "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
67096                              (long) x->t,
67097                              (long) x->regconst,
67098                              (duk_tval *) duk_get_tval(thr, x->valstack_idx),
67099                              (long) forced_reg,
67100                              (unsigned long) flags,
67101                              (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
67102                              (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
67103                              (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
67104
67105         switch (x->t) {
67106         case DUK_ISPEC_VALUE: {
67107                 duk_tval *tv;
67108
67109                 tv = DUK_GET_TVAL_POSIDX(thr, x->valstack_idx);
67110                 DUK_ASSERT(tv != NULL);
67111
67112                 switch (DUK_TVAL_GET_TAG(tv)) {
67113                 case DUK_TAG_UNDEFINED: {
67114                         /* Note: although there is no 'undefined' literal, undefined
67115                          * values can occur during compilation as a result of e.g.
67116                          * the 'void' operator.
67117                          */
67118                         duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
67119                         duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, dest);
67120                         return dest;
67121                 }
67122                 case DUK_TAG_NULL: {
67123                         duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
67124                         duk__emit_bc(comp_ctx, DUK_OP_LDNULL, dest);
67125                         return dest;
67126                 }
67127                 case DUK_TAG_BOOLEAN: {
67128                         duk_regconst_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
67129                         duk__emit_bc(comp_ctx,
67130                                      (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_OP_LDTRUE : DUK_OP_LDFALSE),
67131                                      dest);
67132                         return dest;
67133                 }
67134                 case DUK_TAG_POINTER: {
67135                         DUK_UNREACHABLE();
67136                         break;
67137                 }
67138                 case DUK_TAG_STRING: {
67139                         duk_hstring *h;
67140                         duk_regconst_t dest;
67141                         duk_regconst_t constidx;
67142
67143                         h = DUK_TVAL_GET_STRING(tv);
67144                         DUK_UNREF(h);
67145                         DUK_ASSERT(h != NULL);
67146
67147 #if 0  /* XXX: to be implemented? */
67148                         /* Use special opcodes to load short strings */
67149                         if (DUK_HSTRING_GET_BYTELEN(h) <= 2) {
67150                                 /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */
67151                         } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) {
67152                                 /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
67153                         }
67154 #endif
67155                         duk_dup(thr, x->valstack_idx);
67156                         constidx = duk__getconst(comp_ctx);
67157
67158                         if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
67159                                 return constidx;
67160                         }
67161
67162                         dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
67163                         duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
67164                         return dest;
67165                 }
67166                 case DUK_TAG_OBJECT: {
67167                         DUK_UNREACHABLE();
67168                         break;
67169                 }
67170                 case DUK_TAG_BUFFER: {
67171                         DUK_UNREACHABLE();
67172                         break;
67173                 }
67174                 case DUK_TAG_LIGHTFUNC: {
67175                         DUK_UNREACHABLE();
67176                         break;
67177                 }
67178 #if defined(DUK_USE_FASTINT)
67179                 case DUK_TAG_FASTINT:
67180 #endif
67181                 default: {
67182                         /* number */
67183                         duk_regconst_t dest;
67184                         duk_regconst_t constidx;
67185                         duk_double_t dval;
67186                         duk_int32_t ival;
67187
67188                         DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
67189                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
67190                         dval = DUK_TVAL_GET_NUMBER(tv);
67191
67192                         if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
67193                                 /* A number can be loaded either through a constant, using
67194                                  * LDINT, or using LDINT+LDINTX.  LDINT is always a size win,
67195                                  * LDINT+LDINTX is not if the constant is used multiple times.
67196                                  * Currently always prefer LDINT+LDINTX over a double constant.
67197                                  */
67198
67199                                 if (duk_is_whole_get_int32_nonegzero(dval, &ival)) {
67200                                         dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
67201                                         duk__emit_load_int32(comp_ctx, dest, ival);
67202                                         return dest;
67203                                 }
67204                         }
67205
67206                         duk_dup(thr, x->valstack_idx);
67207                         constidx = duk__getconst(comp_ctx);
67208
67209                         if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
67210                                 return constidx;
67211                         } else {
67212                                 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
67213                                 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, constidx);
67214                                 return dest;
67215                         }
67216                 }
67217                 }  /* end switch */
67218                 goto fail_internal;  /* never here */
67219         }
67220         case DUK_ISPEC_REGCONST: {
67221                 if (forced_reg >= 0) {
67222                         if (DUK__ISCONST(x->regconst)) {
67223                                 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst);
67224                         } else if (x->regconst != forced_reg) {
67225                                 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
67226                         } else {
67227                                 ; /* already in correct reg */
67228                         }
67229                         return forced_reg;
67230                 }
67231
67232                 DUK_ASSERT(forced_reg < 0);
67233                 if (DUK__ISCONST(x->regconst)) {
67234                         if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
67235                                 duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx);
67236                                 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, x->regconst);
67237                                 return dest;
67238                         }
67239                         return x->regconst;
67240                 }
67241
67242                 DUK_ASSERT(forced_reg < 0 && !DUK__ISCONST(x->regconst));
67243                 if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISREG_TEMP(comp_ctx, x->regconst)) {
67244                         duk_regconst_t dest = DUK__ALLOCTEMP(comp_ctx);
67245                         duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, x->regconst);
67246                         return dest;
67247                 }
67248                 return x->regconst;
67249         }
67250         default: {
67251                 break;  /* never here */
67252         }
67253         }
67254
67255  fail_internal:
67256         DUK_ERROR_INTERNAL(thr);
67257         DUK_WO_NORETURN(return 0;);
67258 }
67259
67260 DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_regconst_t forced_reg) {
67261         DUK_ASSERT(forced_reg >= 0);
67262         (void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
67263 }
67264
67265 /* Coerce an duk_ivalue to a 'plain' value by generating the necessary
67266  * arithmetic operations, property access, or variable access bytecode.
67267  * The duk_ivalue argument ('x') is converted into a plain value as a
67268  * side effect.
67269  */
67270 DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_regconst_t forced_reg) {
67271         duk_hthread *thr = comp_ctx->thr;
67272
67273         DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
67274                              "forced_reg=%ld",
67275                              (long) x->t, (long) x->op,
67276                              (long) x->x1.t, (long) x->x1.regconst,
67277                              (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx),
67278                              (long) x->x2.t, (long) x->x2.regconst,
67279                              (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx),
67280                              (long) forced_reg));
67281
67282         switch (x->t) {
67283         case DUK_IVAL_PLAIN: {
67284                 return;
67285         }
67286         /* XXX: support unary arithmetic ivalues (useful?) */
67287         case DUK_IVAL_ARITH: {
67288                 duk_regconst_t arg1;
67289                 duk_regconst_t arg2;
67290                 duk_regconst_t dest;
67291                 duk_tval *tv1;
67292                 duk_tval *tv2;
67293
67294                 DUK_DDD(DUK_DDDPRINT("arith to plain conversion"));
67295
67296                 /* inline arithmetic check for constant values */
67297                 /* XXX: use the exactly same arithmetic function here as in executor */
67298                 if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
67299                         tv1 = DUK_GET_TVAL_POSIDX(thr, x->x1.valstack_idx);
67300                         tv2 = DUK_GET_TVAL_POSIDX(thr, x->x2.valstack_idx);
67301                         DUK_ASSERT(tv1 != NULL);
67302                         DUK_ASSERT(tv2 != NULL);
67303
67304                         DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T",
67305                                              (duk_tval *) tv1,
67306                                              (duk_tval *) tv2));
67307
67308                         if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) {
67309                                 duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1);
67310                                 duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2);
67311                                 duk_double_t d3;
67312                                 duk_bool_t accept_fold = 1;
67313
67314                                 DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
67315                                                      (double) d1, (double) d2, (long) x->op));
67316                                 switch (x->op) {
67317                                 case DUK_OP_ADD: {
67318                                         d3 = d1 + d2;
67319                                         break;
67320                                 }
67321                                 case DUK_OP_SUB: {
67322                                         d3 = d1 - d2;
67323                                         break;
67324                                 }
67325                                 case DUK_OP_MUL: {
67326                                         d3 = d1 * d2;
67327                                         break;
67328                                 }
67329                                 case DUK_OP_DIV: {
67330                                         /* Division-by-zero is undefined
67331                                          * behavior, so rely on a helper.
67332                                          */
67333                                         d3 = duk_double_div(d1, d2);
67334                                         break;
67335                                 }
67336                                 case DUK_OP_EXP: {
67337                                         d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2);
67338                                         break;
67339                                 }
67340                                 default: {
67341                                         d3 = 0.0;  /* Won't be used, but silence MSVC /W4 warning. */
67342                                         accept_fold = 0;
67343                                         break;
67344                                 }
67345                                 }
67346
67347                                 if (accept_fold) {
67348                                         duk_double_union du;
67349                                         du.d = d3;
67350                                         DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
67351                                         d3 = du.d;
67352
67353                                         x->t = DUK_IVAL_PLAIN;
67354                                         DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
67355                                         DUK_TVAL_SET_NUMBER(tv1, d3);  /* old value is number: no refcount */
67356                                         return;
67357                                 }
67358                         } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) {
67359                                 /* Inline string concatenation.  No need to check for
67360                                  * symbols, as all inputs are valid ECMAScript strings.
67361                                  */
67362                                 duk_dup(thr, x->x1.valstack_idx);
67363                                 duk_dup(thr, x->x2.valstack_idx);
67364                                 duk_concat(thr, 2);
67365                                 duk_replace(thr, x->x1.valstack_idx);
67366                                 x->t = DUK_IVAL_PLAIN;
67367                                 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
67368                                 return;
67369                         }
67370                 }
67371
67372                 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
67373                 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
67374
67375                 /* If forced reg, use it as destination.  Otherwise try to
67376                  * use either coerced ispec if it is a temporary.
67377                  */
67378                 if (forced_reg >= 0) {
67379                         dest = forced_reg;
67380                 } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) {
67381                         dest = arg1;
67382                 } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) {
67383                         dest = arg2;
67384                 } else {
67385                         dest = DUK__ALLOCTEMP(comp_ctx);
67386                 }
67387
67388                 DUK_ASSERT(DUK__ISREG(dest));
67389                 duk__emit_a_b_c(comp_ctx, x->op | DUK__EMIT_FLAG_BC_REGCONST, dest, arg1, arg2);
67390
67391                 duk__ivalue_regconst(x, dest);
67392                 return;
67393         }
67394         case DUK_IVAL_PROP: {
67395                 /* XXX: very similar to DUK_IVAL_ARITH - merge? */
67396                 duk_regconst_t arg1;
67397                 duk_regconst_t arg2;
67398                 duk_regconst_t dest;
67399
67400                 /* Need a short reg/const, does not have to be a mutable temp. */
67401                 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
67402                 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
67403
67404                 /* Pick a destination register.  If either base value or key
67405                  * happens to be a temp value, reuse it as the destination.
67406                  *
67407                  * XXX: The temp must be a "mutable" one, i.e. such that no
67408                  * other expression is using it anymore.  Here this should be
67409                  * the case because the value of a property access expression
67410                  * is neither the base nor the key, but the lookup result.
67411                  */
67412
67413                 if (forced_reg >= 0) {
67414                         dest = forced_reg;
67415                 } else if (DUK__ISREG_TEMP(comp_ctx, arg1)) {
67416                         dest = arg1;
67417                 } else if (DUK__ISREG_TEMP(comp_ctx, arg2)) {
67418                         dest = arg2;
67419                 } else {
67420                         dest = DUK__ALLOCTEMP(comp_ctx);
67421                 }
67422
67423                 duk__emit_a_b_c(comp_ctx,
67424                                 DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
67425                                 dest,
67426                                 arg1,
67427                                 arg2);
67428
67429                 duk__ivalue_regconst(x, dest);
67430                 return;
67431         }
67432         case DUK_IVAL_VAR: {
67433                 /* x1 must be a string */
67434                 duk_regconst_t dest;
67435                 duk_regconst_t reg_varbind;
67436                 duk_regconst_t rc_varname;
67437
67438                 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
67439
67440                 duk_dup(thr, x->x1.valstack_idx);
67441                 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
67442                         duk__ivalue_regconst(x, reg_varbind);
67443                 } else {
67444                         dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
67445                         duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, dest, rc_varname);
67446                         duk__ivalue_regconst(x, dest);
67447                 }
67448                 return;
67449         }
67450         case DUK_IVAL_NONE:
67451         default: {
67452                 DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x->t));
67453                 break;
67454         }
67455         }
67456
67457         DUK_ERROR_INTERNAL(thr);
67458         DUK_WO_NORETURN(return;);
67459 }
67460
67461 /* evaluate to plain value, no forced register (temp/bound reg both ok) */
67462 DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
67463         duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
67464 }
67465
67466 /* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
67467 DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
67468         duk_regconst_t temp;
67469
67470         /* If duk__ivalue_toplain_raw() allocates a temp, forget it and
67471          * restore next temp state.
67472          */
67473         temp = DUK__GETTEMP(comp_ctx);
67474         duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
67475         DUK__SETTEMP(comp_ctx, temp);
67476 }
67477
67478 /* Coerce an duk_ivalue to a register or constant; result register may
67479  * be a temp or a bound register.
67480  *
67481  * The duk_ivalue argument ('x') is converted into a regconst as a
67482  * side effect.
67483  */
67484 DUK_LOCAL
67485 duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
67486                                           duk_ivalue *x,
67487                                           duk_regconst_t forced_reg,
67488                                           duk_small_uint_t flags) {
67489         duk_hthread *thr = comp_ctx->thr;
67490         duk_regconst_t reg;
67491         DUK_UNREF(thr);
67492
67493         DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
67494                              "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
67495                              (long) x->t, (long) x->op,
67496                              (long) x->x1.t, (long) x->x1.regconst,
67497                              (duk_tval *) duk_get_tval(thr, x->x1.valstack_idx),
67498                              (long) x->x2.t, (long) x->x2.regconst,
67499                              (duk_tval *) duk_get_tval(thr, x->x2.valstack_idx),
67500                              (long) forced_reg,
67501                              (unsigned long) flags,
67502                              (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
67503                              (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
67504                              (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
67505
67506         /* first coerce to a plain value */
67507         duk__ivalue_toplain_raw(comp_ctx, x, forced_reg);
67508         DUK_ASSERT(x->t == DUK_IVAL_PLAIN);
67509
67510         /* then to a register */
67511         reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
67512         duk__ivalue_regconst(x, reg);
67513
67514         return reg;
67515 }
67516
67517 DUK_LOCAL duk_regconst_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
67518         return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
67519 }
67520
67521 #if 0  /* unused */
67522 DUK_LOCAL duk_regconst_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
67523         return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
67524 }
67525 #endif
67526
67527 DUK_LOCAL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg) {
67528         DUK_ASSERT(forced_reg >= 0);
67529         (void) duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
67530 }
67531
67532 DUK_LOCAL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
67533         return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
67534 }
67535
67536 DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
67537         return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
67538 }
67539
67540 /* The issues below can be solved with better flags */
67541
67542 /* XXX: many operations actually want toforcedtemp() -- brand new temp? */
67543 /* XXX: need a toplain_ignore() which will only coerce a value to a temp
67544  * register if it might have a side effect.  Side-effect free values do not
67545  * need to be coerced.
67546  */
67547
67548 /*
67549  *  Identifier handling
67550  */
67551
67552 DUK_LOCAL duk_regconst_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
67553         duk_hthread *thr = comp_ctx->thr;
67554         duk_hstring *h_varname;
67555         duk_regconst_t ret;
67556
67557         DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
67558                              (duk_tval *) duk_get_tval(thr, -1)));
67559
67560         /*
67561          *  Special name handling
67562          */
67563
67564         h_varname = duk_known_hstring(thr, -1);
67565
67566         if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
67567                 DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
67568                 comp_ctx->curr_func.id_access_arguments = 1;
67569         }
67570
67571         /*
67572          *  Inside one or more 'with' statements fall back to slow path always.
67573          *  (See e.g. test-stmt-with.js.)
67574          */
67575
67576         if (comp_ctx->curr_func.with_depth > 0) {
67577                 DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
67578                 goto slow_path_own;
67579         }
67580
67581         /*
67582          *  Any catch bindings ("catch (e)") also affect identifier binding.
67583          *
67584          *  Currently, the varmap is modified for the duration of the catch
67585          *  clause to ensure any identifier accesses with the catch variable
67586          *  name will use slow path.
67587          */
67588
67589         duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
67590         if (duk_is_number(thr, -1)) {
67591                 ret = duk_to_int(thr, -1);
67592                 duk_pop(thr);
67593         } else {
67594                 duk_pop(thr);
67595                 if (comp_ctx->curr_func.catch_depth > 0 || comp_ctx->curr_func.with_depth > 0) {
67596                         DUK_DDD(DUK_DDDPRINT("slow path access from inside a try-catch or with needs _Varmap"));
67597                         goto slow_path_own;
67598                 } else {
67599                         /* In this case we're doing a variable lookup that doesn't
67600                          * match our own variables, so _Varmap won't be needed at
67601                          * run time.
67602                          */
67603                         DUK_DDD(DUK_DDDPRINT("slow path access outside of try-catch and with, no need for _Varmap"));
67604                         goto slow_path_notown;
67605                 }
67606         }
67607
67608         DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret));
67609         return ret;
67610
67611  slow_path_notown:
67612         DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, not own variable"));
67613
67614         comp_ctx->curr_func.id_access_slow = 1;
67615         return (duk_regconst_t) -1;
67616
67617  slow_path_own:
67618         DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, may be own variable"));
67619
67620         comp_ctx->curr_func.id_access_slow = 1;
67621         comp_ctx->curr_func.id_access_slow_own = 1;
67622         return (duk_regconst_t) -1;
67623 }
67624
67625 /* Lookup an identifier name in the current varmap, indicating whether the
67626  * identifier is register-bound and if not, allocating a constant for the
67627  * identifier name.  Returns 1 if register-bound, 0 otherwise.  Caller can
67628  * also check (out_reg_varbind >= 0) to check whether or not identifier is
67629  * register bound.  The caller must NOT use out_rc_varname at all unless
67630  * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
67631  * is unsigned and doesn't have a "unused" / none value.
67632  */
67633 DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
67634         duk_hthread *thr = comp_ctx->thr;
67635         duk_regconst_t reg_varbind;
67636         duk_regconst_t rc_varname;
67637
67638         /* [ ... varname ] */
67639
67640         duk_dup_top(thr);
67641         reg_varbind = duk__lookup_active_register_binding(comp_ctx);
67642
67643         if (reg_varbind >= 0) {
67644                 *out_reg_varbind = reg_varbind;
67645                 *out_rc_varname = 0;  /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
67646                 duk_pop(thr);
67647                 return 1;
67648         } else {
67649                 rc_varname = duk__getconst(comp_ctx);
67650                 *out_reg_varbind = -1;
67651                 *out_rc_varname = rc_varname;
67652                 return 0;
67653         }
67654 }
67655
67656 /*
67657  *  Label handling
67658  *
67659  *  Labels are initially added with flags prohibiting both break and continue.
67660  *  When the statement type is finally uncovered (after potentially multiple
67661  *  labels), all the labels are updated to allow/prohibit break and continue.
67662  */
67663
67664 DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) {
67665         duk_hthread *thr = comp_ctx->thr;
67666         duk_size_t n;
67667         duk_size_t new_size;
67668         duk_uint8_t *p;
67669         duk_labelinfo *li_start, *li;
67670
67671         /* Duplicate (shadowing) labels are not allowed, except for the empty
67672          * labels (which are used as default labels for switch and iteration
67673          * statements).
67674          *
67675          * We could also allow shadowing of non-empty pending labels without any
67676          * other issues than breaking the required label shadowing requirements
67677          * of the E5 specification, see Section 12.12.
67678          */
67679
67680         p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
67681         li_start = (duk_labelinfo *) (void *) p;
67682         li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
67683         n = (duk_size_t) (li - li_start);
67684
67685         while (li > li_start) {
67686                 li--;
67687
67688                 if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
67689                         DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL);
67690                         DUK_WO_NORETURN(return;);
67691                 }
67692         }
67693
67694         duk_push_hstring(thr, h_label);
67695         DUK_ASSERT(n <= DUK_UARRIDX_MAX);  /* label limits */
67696         (void) duk_put_prop_index(thr, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
67697
67698         new_size = (n + 1) * sizeof(duk_labelinfo);
67699         duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
67700         /* XXX: slack handling, slow now */
67701
67702         /* relookup after possible realloc */
67703         p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
67704         li_start = (duk_labelinfo *) (void *) p;
67705         DUK_UNREF(li_start);  /* silence scan-build warning */
67706         li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
67707         li--;
67708
67709         /* Labels can be used for iteration statements but also for other statements,
67710          * in particular a label can be used for a block statement.  All cases of a
67711          * named label accept a 'break' so that flag is set here.  Iteration statements
67712          * also allow 'continue', so that flag is updated when we figure out the
67713          * statement type.
67714          */
67715
67716         li->flags = DUK_LABEL_FLAG_ALLOW_BREAK;
67717         li->label_id = label_id;
67718         li->h_label = h_label;
67719         li->catch_depth = comp_ctx->curr_func.catch_depth;   /* catch depth from current func */
67720         li->pc_label = pc_label;
67721
67722         DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld",
67723                              (unsigned long) li->flags, (long) li->label_id, (duk_heaphdr *) li->h_label,
67724                              (long) li->catch_depth, (long) li->pc_label));
67725 }
67726
67727 /* Update all labels with matching label_id. */
67728 DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags) {
67729         duk_uint8_t *p;
67730         duk_labelinfo *li_start, *li;
67731
67732         p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx->thr->heap, comp_ctx->curr_func.h_labelinfos);
67733         li_start = (duk_labelinfo *) (void *) p;
67734         li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
67735
67736         /* Match labels starting from latest; once label_id no longer matches, we can
67737          * safely exit without checking the rest of the labels (only the topmost labels
67738          * are ever updated).
67739          */
67740         while (li > li_start) {
67741                 li--;
67742
67743                 if (li->label_id != label_id) {
67744                         break;
67745                 }
67746
67747                 DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld",
67748                                      (void *) li, (long) label_id, (long) flags));
67749
67750                 li->flags = flags;
67751         }
67752 }
67753
67754 /* Lookup active label information.  Break/continue distinction is necessary to handle switch
67755  * statement related labels correctly: a switch will only catch a 'break', not a 'continue'.
67756  *
67757  * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled
67758  * iteration and switch statements) can.  A break will match the closest unlabelled or labelled
67759  * statement.  A continue will match the closest unlabelled or labelled iteration statement.  It is
67760  * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot
67761  * be duplicated, the continue cannot match any valid label outside the switch.
67762  *
67763  * A side effect of these rules is that a LABEL statement related to a switch should never actually
67764  * catch a continue abrupt completion at run-time.  Hence an INVALID opcode can be placed in the
67765  * continue slot of the switch's LABEL statement.
67766  */
67767
67768 /* XXX: awkward, especially the bunch of separate output values -> output struct? */
67769 DUK_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) {
67770         duk_hthread *thr = comp_ctx->thr;
67771         duk_uint8_t *p;
67772         duk_labelinfo *li_start, *li_end, *li;
67773         duk_bool_t match = 0;
67774
67775         DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
67776                              (duk_heaphdr *) h_label, (long) is_break));
67777
67778         DUK_UNREF(thr);
67779
67780         p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
67781         li_start = (duk_labelinfo *) (void *) p;
67782         li_end = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
67783         li = li_end;
67784
67785         /* Match labels starting from latest label because there can be duplicate empty
67786          * labels in the label set.
67787          */
67788         while (li > li_start) {
67789                 li--;
67790
67791                 if (li->h_label != h_label) {
67792                         DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O",
67793                                              (long) (li - li_start),
67794                                              (duk_heaphdr *) li->h_label,
67795                                              (duk_heaphdr *) h_label));
67796                         continue;
67797                 }
67798
67799                 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)",
67800                                      (long) (li - li_start), (duk_heaphdr *) h_label));
67801
67802                 /* currently all labels accept a break, so no explicit check for it now */
67803                 DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK);
67804
67805                 if (is_break) {
67806                         /* break matches always */
67807                         match = 1;
67808                         break;
67809                 } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) {
67810                         /* iteration statements allow continue */
67811                         match = 1;
67812                         break;
67813                 } else {
67814                         /* continue matched this label -- we can only continue if this is the empty
67815                          * label, for which duplication is allowed, and thus there is hope of
67816                          * finding a match deeper in the label stack.
67817                          */
67818                         if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
67819                                 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
67820                                 DUK_WO_NORETURN(return;);
67821                         } else {
67822                                 DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not "
67823                                                      "allow a continue -> continue lookup deeper in label stack"));
67824                         }
67825                 }
67826         }
67827         /* XXX: match flag is awkward, rework */
67828         if (!match) {
67829                 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
67830                 DUK_WO_NORETURN(return;);
67831         }
67832
67833         DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld",
67834                              (duk_heaphdr *) h_label, (long) li->label_id,
67835                              (long) li->catch_depth, (long) li->pc_label));
67836
67837         *out_label_id = li->label_id;
67838         *out_label_catch_depth = li->catch_depth;
67839         *out_label_pc = li->pc_label;
67840         *out_is_closest = (li == li_end - 1);
67841 }
67842
67843 DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_size_t len) {
67844         duk_hthread *thr = comp_ctx->thr;
67845
67846         duk_set_length(thr, comp_ctx->curr_func.labelnames_idx, len);
67847         duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * len);
67848 }
67849
67850 /*
67851  *  Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
67852  *
67853  *  - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal)
67854  *  - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator)
67855  *  - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token
67856  */
67857
67858 /* object literal key tracking flags */
67859 #define DUK__OBJ_LIT_KEY_PLAIN  (1 << 0)  /* key encountered as a plain property */
67860 #define DUK__OBJ_LIT_KEY_GET    (1 << 1)  /* key encountered as a getter */
67861 #define DUK__OBJ_LIT_KEY_SET    (1 << 2)  /* key encountered as a setter */
67862
67863 DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
67864         duk_hthread *thr = comp_ctx->thr;
67865         duk_regconst_t reg_obj;                 /* result reg */
67866         duk_regconst_t reg_temp;                /* temp reg */
67867         duk_regconst_t temp_start;              /* temp reg value for start of loop */
67868         duk_small_uint_t max_init_values;  /* max # of values initialized in one MPUTARR set */
67869         duk_small_uint_t num_values;       /* number of values in current MPUTARR set */
67870         duk_uarridx_t curr_idx;            /* current (next) array index */
67871         duk_uarridx_t start_idx;           /* start array index of current MPUTARR set */
67872         duk_uarridx_t init_idx;            /* last array index explicitly initialized, +1 */
67873         duk_bool_t require_comma;          /* next loop requires a comma */
67874 #if !defined(DUK_USE_PREFER_SIZE)
67875         duk_int_t pc_newarr;
67876         duk_compiler_instr *instr;
67877 #endif
67878
67879         /* DUK_TOK_LBRACKET already eaten, current token is right after that */
67880         DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
67881
67882         max_init_values = DUK__MAX_ARRAY_INIT_VALUES;  /* XXX: depend on available temps? */
67883
67884         reg_obj = DUK__ALLOCTEMP(comp_ctx);
67885 #if !defined(DUK_USE_PREFER_SIZE)
67886         pc_newarr = duk__get_current_pc(comp_ctx);
67887 #endif
67888         duk__emit_bc(comp_ctx, DUK_OP_NEWARR, reg_obj);  /* XXX: patch initial size hint afterwards? */
67889         temp_start = DUK__GETTEMP(comp_ctx);
67890
67891         /*
67892          *  Emit initializers in sets of maximum max_init_values.
67893          *  Corner cases such as single value initializers do not have
67894          *  special handling now.
67895          *
67896          *  Elided elements must not be emitted as 'undefined' values,
67897          *  because such values would be enumerable (which is incorrect).
67898          *  Also note that trailing elisions must be reflected in the
67899          *  length of the final array but cause no elements to be actually
67900          *  inserted.
67901          */
67902
67903         curr_idx = 0;
67904         init_idx = 0;         /* tracks maximum initialized index + 1 */
67905         start_idx = 0;
67906         require_comma = 0;
67907
67908         for (;;) {
67909                 num_values = 0;
67910                 DUK__SETTEMP(comp_ctx, temp_start);
67911
67912                 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
67913                         break;
67914                 }
67915
67916                 for (;;) {
67917                         if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
67918                                 /* the outer loop will recheck and exit */
67919                                 break;
67920                         }
67921
67922                         /* comma check */
67923                         if (require_comma) {
67924                                 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
67925                                         /* comma after a value, expected */
67926                                         duk__advance(comp_ctx);
67927                                         require_comma = 0;
67928                                         continue;
67929                                 } else {
67930                                         goto syntax_error;
67931                                 }
67932                         } else {
67933                                 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
67934                                         /* elision - flush */
67935                                         curr_idx++;
67936                                         duk__advance(comp_ctx);
67937                                         /* if num_values > 0, MPUTARR emitted by outer loop after break */
67938                                         break;
67939                                 }
67940                         }
67941                         /* else an array initializer element */
67942
67943                         /* initial index */
67944                         if (num_values == 0) {
67945                                 start_idx = curr_idx;
67946                                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
67947                                 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int32_t) start_idx);
67948                         }
67949
67950                         reg_temp = DUK__ALLOCTEMP(comp_ctx);   /* alloc temp just in case, to update max temp */
67951                         DUK__SETTEMP(comp_ctx, reg_temp);
67952                         duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
67953                         DUK__SETTEMP(comp_ctx, reg_temp + 1);
67954
67955                         num_values++;
67956                         curr_idx++;
67957                         require_comma = 1;
67958
67959                         if (num_values >= max_init_values) {
67960                                 /* MPUTARR emitted by outer loop */
67961                                 break;
67962                         }
67963                 }
67964
67965                 if (num_values > 0) {
67966                         /* - A is a source register (it's not a write target, but used
67967                          *   to identify the target object) but can be shuffled.
67968                          * - B cannot be shuffled normally because it identifies a range
67969                          *   of registers, the emitter has special handling for this
67970                          *   (the "no shuffle" flag must not be set).
67971                          * - C is a non-register number and cannot be shuffled, but
67972                          *   never needs to be.
67973                          */
67974                         duk__emit_a_b_c(comp_ctx,
67975                                         DUK_OP_MPUTARR |
67976                                             DUK__EMIT_FLAG_NO_SHUFFLE_C |
67977                                             DUK__EMIT_FLAG_A_IS_SOURCE,
67978                                         reg_obj,
67979                                         temp_start,
67980                                         (duk_regconst_t) (num_values + 1));
67981                         init_idx = start_idx + num_values;
67982
67983                         /* num_values and temp_start reset at top of outer loop */
67984                 }
67985         }
67986
67987         /* Update initil size for NEWARR, doesn't need to be exact and is
67988          * capped at A field limit.
67989          */
67990 #if !defined(DUK_USE_PREFER_SIZE)
67991         instr = duk__get_instr_ptr(comp_ctx, pc_newarr);
67992         instr->ins |= DUK_ENC_OP_A(0, curr_idx > DUK_BC_A_MAX ? DUK_BC_A_MAX : curr_idx);
67993 #endif
67994
67995         DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
67996         duk__advance(comp_ctx);
67997
67998         DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld",
67999                              (long) curr_idx, (long) init_idx));
68000
68001         /* trailing elisions? */
68002         if (curr_idx > init_idx) {
68003                 /* yes, must set array length explicitly */
68004                 DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length"));
68005                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
68006                 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx);
68007                 duk__emit_a_bc(comp_ctx,
68008                                DUK_OP_SETALEN | DUK__EMIT_FLAG_A_IS_SOURCE,
68009                                reg_obj,
68010                                reg_temp);
68011         }
68012
68013         DUK__SETTEMP(comp_ctx, temp_start);
68014
68015         duk__ivalue_regconst(res, reg_obj);
68016         return;
68017
68018  syntax_error:
68019         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL);
68020         DUK_WO_NORETURN(return;);
68021 }
68022
68023 typedef struct {
68024         duk_regconst_t reg_obj;
68025         duk_regconst_t temp_start;
68026         duk_small_uint_t num_pairs;
68027         duk_small_uint_t num_total_pairs;
68028 } duk__objlit_state;
68029
68030 DUK_LOCAL void duk__objlit_flush_keys(duk_compiler_ctx *comp_ctx, duk__objlit_state *st) {
68031         if (st->num_pairs > 0) {
68032                 /* - A is a source register (it's not a write target, but used
68033                  *   to identify the target object) but can be shuffled.
68034                  * - B cannot be shuffled normally because it identifies a range
68035                  *   of registers, the emitter has special handling for this
68036                  *   (the "no shuffle" flag must not be set).
68037                  * - C is a non-register number and cannot be shuffled, but
68038                  *   never needs to be.
68039                  */
68040                 DUK_ASSERT(st->num_pairs > 0);
68041                 duk__emit_a_b_c(comp_ctx,
68042                                 DUK_OP_MPUTOBJ |
68043                                     DUK__EMIT_FLAG_NO_SHUFFLE_C |
68044                                     DUK__EMIT_FLAG_A_IS_SOURCE,
68045                                 st->reg_obj,
68046                                 st->temp_start,
68047                                 (duk_regconst_t) (st->num_pairs * 2));
68048                 st->num_total_pairs += st->num_pairs;
68049                 st->num_pairs = 0;
68050         }
68051         DUK__SETTEMP(comp_ctx, st->temp_start);
68052 }
68053
68054 DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_token *tok, duk_regconst_t reg_temp) {
68055         if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t_nores == DUK_TOK_STRING) {
68056                 /* same handling for identifiers and strings */
68057                 DUK_ASSERT(tok->str1 != NULL);
68058                 duk_push_hstring(comp_ctx->thr, tok->str1);
68059         } else if (tok->t == DUK_TOK_NUMBER) {
68060                 /* numbers can be loaded as numbers and coerced on the fly */
68061                 duk_push_number(comp_ctx->thr, tok->num);
68062         } else {
68063                 return 1;  /* error */
68064         }
68065
68066         duk__ivalue_plain_fromstack(comp_ctx, res);
68067         DUK__SETTEMP(comp_ctx, reg_temp + 1);
68068         duk__ivalue_toforcedreg(comp_ctx, res, reg_temp);
68069         DUK__SETTEMP(comp_ctx, reg_temp + 1);
68070         return 0;
68071 }
68072
68073 DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
68074         duk_hthread *thr = comp_ctx->thr;
68075         duk__objlit_state st;
68076         duk_regconst_t reg_temp;          /* temp reg */
68077         duk_small_uint_t max_init_pairs;  /* max # of key-value pairs initialized in one MPUTOBJ set */
68078         duk_bool_t first;                 /* first value: comma must not precede the value */
68079         duk_bool_t is_set, is_get;        /* temps */
68080 #if !defined(DUK_USE_PREFER_SIZE)
68081         duk_int_t pc_newobj;
68082         duk_compiler_instr *instr;
68083 #endif
68084
68085         DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
68086
68087         max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS;  /* XXX: depend on available temps? */
68088
68089         st.reg_obj = DUK__ALLOCTEMP(comp_ctx);    /* target object */
68090         st.temp_start = DUK__GETTEMP(comp_ctx);   /* start of MPUTOBJ argument list */
68091         st.num_pairs = 0;                         /* number of key/value pairs emitted for current MPUTOBJ set */
68092         st.num_total_pairs = 0;                   /* number of key/value pairs emitted overall */
68093
68094 #if !defined(DUK_USE_PREFER_SIZE)
68095         pc_newobj = duk__get_current_pc(comp_ctx);
68096 #endif
68097         duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, st.reg_obj);
68098
68099         /*
68100          *  Emit initializers in sets of maximum max_init_pairs keys.
68101          *  Setter/getter is handled separately and terminates the
68102          *  current set of initializer values.  Corner cases such as
68103          *  single value initializers do not have special handling now.
68104          */
68105
68106         first = 1;
68107         for (;;) {
68108                 /*
68109                  *  ES5 and ES2015+ provide a lot of different PropertyDefinition
68110                  *  formats, see http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer.
68111                  *
68112                  *  PropertyName can be IdentifierName (includes reserved words), a string
68113                  *  literal, or a number literal.  Note that IdentifierName allows 'get' and
68114                  *  'set' too, so we need to look ahead to the next token to distinguish:
68115                  *
68116                  *     { get : 1 }
68117                  *
68118                  *  and
68119                  *
68120                  *     { get foo() { return 1 } }
68121                  *     { get get() { return 1 } }    // 'get' as getter propertyname
68122                  *
68123                  *  Finally, a trailing comma is allowed.
68124                  *
68125                  *  Key name is coerced to string at compile time (and ends up as a
68126                  *  a string constant) even for numeric keys (e.g. "{1:'foo'}").
68127                  *  These could be emitted using e.g. LDINT, but that seems hardly
68128                  *  worth the effort and would increase code size.
68129                  */
68130
68131                 DUK_DDD(DUK_DDDPRINT("object literal loop, curr_token->t = %ld",
68132                                      (long) comp_ctx->curr_token.t));
68133
68134                 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
68135                         break;
68136                 }
68137
68138                 if (first) {
68139                         first = 0;
68140                 } else {
68141                         if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
68142                                 goto syntax_error;
68143                         }
68144                         duk__advance(comp_ctx);
68145                         if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
68146                                 /* trailing comma followed by rcurly */
68147                                 break;
68148                         }
68149                 }
68150
68151                 /* Advance to get one step of lookup. */
68152                 duk__advance(comp_ctx);
68153
68154                 /* Flush current MPUTOBJ if enough many pairs gathered. */
68155                 if (st.num_pairs >= max_init_pairs) {
68156                         duk__objlit_flush_keys(comp_ctx, &st);
68157                         DUK_ASSERT(st.num_pairs == 0);
68158                 }
68159
68160                 /* Reset temp register state and reserve reg_temp and
68161                  * reg_temp + 1 for handling the current property.
68162                  */
68163                 DUK__SETTEMP(comp_ctx, st.temp_start + 2 * (duk_regconst_t) st.num_pairs);
68164                 reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
68165
68166                 /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
68167                  * currently treats them always like ordinary identifiers (DUK_TOK_GET
68168                  * and DUK_TOK_SET are unused).  They need to be detected based on the
68169                  * identifier string content.
68170                  */
68171
68172                 is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
68173                           comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
68174                 is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
68175                           comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
68176                 if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
68177                         /* getter/setter */
68178                         duk_int_t fnum;
68179
68180                         duk__objlit_flush_keys(comp_ctx, &st);
68181                         DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start);  /* 2 regs are guaranteed to be allocated w.r.t. temp_max */
68182                         reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
68183
68184                         if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->curr_token, reg_temp) != 0) {
68185                                 goto syntax_error;
68186                         }
68187
68188                         /* curr_token = get/set name */
68189                         fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_GETSET);
68190
68191                         duk__emit_a_bc(comp_ctx,
68192                                        DUK_OP_CLOSURE,
68193                                        st.temp_start + 1,
68194                                        (duk_regconst_t) fnum);
68195
68196                         /* Slot C is used in a non-standard fashion (range of regs),
68197                          * emitter code has special handling for it (must not set the
68198                          * "no shuffle" flag).
68199                          */
68200                         duk__emit_a_bc(comp_ctx,
68201                                       (is_get ? DUK_OP_INITGET : DUK_OP_INITSET) | DUK__EMIT_FLAG_A_IS_SOURCE,
68202                                       st.reg_obj,
68203                                       st.temp_start);   /* temp_start+0 = key, temp_start+1 = closure */
68204
68205                         DUK_ASSERT(st.num_pairs == 0);  /* temp state is reset on next loop */
68206 #if defined(DUK_USE_ES6)
68207                 } else if (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
68208                            (comp_ctx->curr_token.t == DUK_TOK_COMMA || comp_ctx->curr_token.t == DUK_TOK_RCURLY)) {
68209                         duk_bool_t load_rc;
68210
68211                         load_rc = duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp);
68212                         DUK_UNREF(load_rc);
68213                         DUK_ASSERT(load_rc == 0);  /* always succeeds because token is identifier */
68214
68215                         duk__ivalue_var_hstring(comp_ctx, res, comp_ctx->prev_token.str1);
68216                         DUK_ASSERT(DUK__GETTEMP(comp_ctx) == reg_temp + 1);
68217                         duk__ivalue_toforcedreg(comp_ctx, res, reg_temp + 1);
68218
68219                         st.num_pairs++;
68220                 } else if ((comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER ||
68221                             comp_ctx->prev_token.t == DUK_TOK_STRING ||
68222                             comp_ctx->prev_token.t == DUK_TOK_NUMBER) &&
68223                            comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
68224                         duk_int_t fnum;
68225
68226                         /* Parsing-wise there's a small hickup here: the token parsing
68227                          * state is one step too advanced for the function parse helper
68228                          * compared to other cases.  The current solution is an extra
68229                          * flag to indicate whether function parsing should use the
68230                          * current or the previous token to starting parsing from.
68231                          */
68232
68233                         if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) {
68234                                 goto syntax_error;
68235                         }
68236
68237                         fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_USE_PREVTOKEN | DUK__FUNC_FLAG_METDEF);
68238
68239                         duk__emit_a_bc(comp_ctx,
68240                                        DUK_OP_CLOSURE,
68241                                        reg_temp + 1,
68242                                        (duk_regconst_t) fnum);
68243
68244                         st.num_pairs++;
68245 #endif  /* DUK_USE_ES6 */
68246                 } else {
68247 #if defined(DUK_USE_ES6)
68248                         if (comp_ctx->prev_token.t == DUK_TOK_LBRACKET) {
68249                                 /* ES2015 computed property name.  Executor ToPropertyKey()
68250                                  * coerces the key at runtime.
68251                                  */
68252                                 DUK__SETTEMP(comp_ctx, reg_temp);
68253                                 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR, reg_temp);
68254                                 duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
68255
68256                                 /* XXX: If next token is '(' we're dealing with
68257                                  * the method shorthand with a computed name,
68258                                  * e.g. { [Symbol.for('foo')](a,b) {} }.  This
68259                                  * form is not yet supported and causes a
68260                                  * SyntaxError on the DUK_TOK_COLON check below.
68261                                  */
68262                         }
68263                         else
68264 #endif  /* DUK_USE_ES6 */
68265                         {
68266                                 if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) {
68267                                         goto syntax_error;
68268                                 }
68269                         }
68270
68271                         duk__advance_expect(comp_ctx, DUK_TOK_COLON);
68272
68273                         DUK__SETTEMP(comp_ctx, reg_temp + 1);
68274                         duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp + 1 /*forced_reg*/);
68275
68276                         st.num_pairs++;
68277                 }
68278         }  /* property loop */
68279
68280         /* Flush remaining properties. */
68281         duk__objlit_flush_keys(comp_ctx, &st);
68282         DUK_ASSERT(st.num_pairs == 0);
68283         DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start);
68284
68285         /* Update initial size for NEWOBJ.  The init size doesn't need to be
68286          * exact as the purpose is just to avoid object resizes in common
68287          * cases.  The size is capped to field A limit, and will be too high
68288          * if the object literal contains duplicate keys (this is harmless but
68289          * increases memory traffic if the object is compacted later on).
68290          */
68291 #if !defined(DUK_USE_PREFER_SIZE)
68292         instr = duk__get_instr_ptr(comp_ctx, pc_newobj);
68293         instr->ins |= DUK_ENC_OP_A(0, st.num_total_pairs > DUK_BC_A_MAX ? DUK_BC_A_MAX : st.num_total_pairs);
68294 #endif
68295
68296         DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
68297         duk__advance(comp_ctx);  /* No RegExp after object literal. */
68298
68299         duk__ivalue_regconst(res, st.reg_obj);
68300         return;
68301
68302  syntax_error:
68303         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL);
68304         DUK_WO_NORETURN(return;);
68305 }
68306
68307 /* Parse argument list.  Arguments are written to temps starting from
68308  * "next temp".  Returns number of arguments parsed.  Expects left paren
68309  * to be already eaten, and eats the right paren before returning.
68310  */
68311 DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
68312         duk_int_t nargs = 0;
68313         duk_regconst_t reg_temp;
68314
68315         /* Note: expect that caller has already eaten the left paren */
68316
68317         DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld",
68318                              (long) comp_ctx->prev_token.t, (long) comp_ctx->curr_token.t));
68319
68320         for (;;) {
68321                 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
68322                         break;
68323                 }
68324                 if (nargs > 0) {
68325                         duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
68326                 }
68327
68328                 /* We want the argument expression value to go to "next temp"
68329                  * without additional moves.  That should almost always be the
68330                  * case, but we double check after expression parsing.
68331                  *
68332                  * This is not the cleanest possible approach.
68333                  */
68334
68335                 reg_temp = DUK__ALLOCTEMP(comp_ctx);  /* bump up "allocated" reg count, just in case */
68336                 DUK__SETTEMP(comp_ctx, reg_temp);
68337
68338                 /* binding power must be high enough to NOT allow comma expressions directly */
68339                 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp);  /* always allow 'in', coerce to 'tr' just in case */
68340
68341                 DUK__SETTEMP(comp_ctx, reg_temp + 1);
68342                 nargs++;
68343
68344                 DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs, (long) reg_temp));
68345         }
68346
68347         /* eat the right paren */
68348         duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);  /* RegExp mode does not matter. */
68349
68350         DUK_DDD(DUK_DDDPRINT("end parsing arguments"));
68351
68352         return nargs;
68353 }
68354
68355 DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
68356         /* empty expressions can be detected conveniently with nud/led counts */
68357         return (comp_ctx->curr_func.nud_count == 0) &&
68358                (comp_ctx->curr_func.led_count == 0);
68359 }
68360
68361 DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
68362         duk_hthread *thr = comp_ctx->thr;
68363         duk_token *tk;
68364         duk_regconst_t temp_at_entry;
68365         duk_small_uint_t tok;
68366         duk_uint32_t args;  /* temp variable to pass constants and flags to shared code */
68367
68368         /*
68369          *  ctx->prev_token     token to process with duk__expr_nud()
68370          *  ctx->curr_token     updated by caller
68371          *
68372          *  Note: the token in the switch below has already been eaten.
68373          */
68374
68375         temp_at_entry = DUK__GETTEMP(comp_ctx);
68376
68377         comp_ctx->curr_func.nud_count++;
68378
68379         tk = &comp_ctx->prev_token;
68380         tok = tk->t;
68381         res->t = DUK_IVAL_NONE;
68382
68383         DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
68384                              (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
68385
68386         switch (tok) {
68387
68388         /* PRIMARY EXPRESSIONS */
68389
68390         case DUK_TOK_THIS: {
68391                 duk_regconst_t reg_temp;
68392                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
68393                 duk__emit_bc(comp_ctx,
68394                              DUK_OP_LDTHIS,
68395                              reg_temp);
68396                 duk__ivalue_regconst(res, reg_temp);
68397                 return;
68398         }
68399         case DUK_TOK_IDENTIFIER: {
68400                 duk__ivalue_var_hstring(comp_ctx, res, tk->str1);
68401                 return;
68402         }
68403         case DUK_TOK_NULL: {
68404                 duk_push_null(thr);
68405                 goto plain_value;
68406         }
68407         case DUK_TOK_TRUE: {
68408                 duk_push_true(thr);
68409                 goto plain_value;
68410         }
68411         case DUK_TOK_FALSE: {
68412                 duk_push_false(thr);
68413                 goto plain_value;
68414         }
68415         case DUK_TOK_NUMBER: {
68416                 duk_push_number(thr, tk->num);
68417                 goto plain_value;
68418         }
68419         case DUK_TOK_STRING: {
68420                 DUK_ASSERT(tk->str1 != NULL);
68421                 duk_push_hstring(thr, tk->str1);
68422                 goto plain_value;
68423         }
68424         case DUK_TOK_REGEXP: {
68425 #if defined(DUK_USE_REGEXP_SUPPORT)
68426                 duk_regconst_t reg_temp;
68427                 duk_regconst_t rc_re_bytecode;  /* const */
68428                 duk_regconst_t rc_re_source;    /* const */
68429
68430                 DUK_ASSERT(tk->str1 != NULL);
68431                 DUK_ASSERT(tk->str2 != NULL);
68432
68433                 DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O",
68434                                      (duk_heaphdr *) tk->str1,
68435                                      (duk_heaphdr *) tk->str2));
68436
68437                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
68438                 duk_push_hstring(thr, tk->str1);
68439                 duk_push_hstring(thr, tk->str2);
68440
68441                 /* [ ... pattern flags ] */
68442
68443                 duk_regexp_compile(thr);
68444
68445                 /* [ ... escaped_source bytecode ] */
68446
68447                 rc_re_bytecode = duk__getconst(comp_ctx);
68448                 rc_re_source = duk__getconst(comp_ctx);
68449
68450                 duk__emit_a_b_c(comp_ctx,
68451                                 DUK_OP_REGEXP | DUK__EMIT_FLAG_BC_REGCONST,
68452                                 reg_temp /*a*/,
68453                                 rc_re_bytecode /*b*/,
68454                                 rc_re_source /*c*/);
68455
68456                 duk__ivalue_regconst(res, reg_temp);
68457                 return;
68458 #else  /* DUK_USE_REGEXP_SUPPORT */
68459                 goto syntax_error;
68460 #endif  /* DUK_USE_REGEXP_SUPPORT */
68461         }
68462         case DUK_TOK_LBRACKET: {
68463                 DUK_DDD(DUK_DDDPRINT("parsing array literal"));
68464                 duk__nud_array_literal(comp_ctx, res);
68465                 return;
68466         }
68467         case DUK_TOK_LCURLY: {
68468                 DUK_DDD(DUK_DDDPRINT("parsing object literal"));
68469                 duk__nud_object_literal(comp_ctx, res);
68470                 return;
68471         }
68472         case DUK_TOK_LPAREN: {
68473                 duk_bool_t prev_allow_in;
68474
68475                 comp_ctx->curr_func.paren_level++;
68476                 prev_allow_in = comp_ctx->curr_func.allow_in;
68477                 comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */
68478
68479                 duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);  /* Expression, terminates at a ')' */
68480
68481                 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);  /* No RegExp after parenthesized expression. */
68482                 comp_ctx->curr_func.allow_in = prev_allow_in;
68483                 comp_ctx->curr_func.paren_level--;
68484                 return;
68485         }
68486
68487         /* MEMBER/NEW/CALL EXPRESSIONS */
68488
68489         case DUK_TOK_NEW: {
68490                 /*
68491                  *  Parsing an expression starting with 'new' is tricky because
68492                  *  there are multiple possible productions deriving from
68493                  *  LeftHandSideExpression which begin with 'new'.
68494                  *
68495                  *  We currently resort to one-token lookahead to distinguish the
68496                  *  cases.  Hopefully this is correct.  The binding power must be
68497                  *  such that parsing ends at an LPAREN (CallExpression) but not at
68498                  *  a PERIOD or LBRACKET (MemberExpression).
68499                  *
68500                  *  See doc/compiler.rst for discussion on the parsing approach,
68501                  *  and testcases/test-dev-new.js for a bunch of documented tests.
68502                  */
68503
68504                 duk_regconst_t reg_target;
68505                 duk_int_t nargs;
68506
68507                 DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
68508
68509                 reg_target = DUK__ALLOCTEMPS(comp_ctx, 2);
68510
68511 #if defined(DUK_USE_ES6)
68512                 if (comp_ctx->curr_token.t == DUK_TOK_PERIOD) {
68513                         /* new.target */
68514                         DUK_DDD(DUK_DDDPRINT("new.target"));
68515                         duk__advance(comp_ctx);
68516                         if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER ||
68517                             !duk_hstring_equals_ascii_cstring(comp_ctx->curr_token.str1, "target")) {
68518                                 goto syntax_error_newtarget;
68519                         }
68520                         if (comp_ctx->curr_func.is_global) {
68521                                 goto syntax_error_newtarget;
68522                         }
68523                         duk__advance(comp_ctx);
68524                         duk__emit_bc(comp_ctx,
68525                                      DUK_OP_NEWTARGET,
68526                                      reg_target);
68527                         duk__ivalue_regconst(res, reg_target);
68528                         return;
68529                 }
68530 #endif  /* DUK_USE_ES6 */
68531
68532                 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
68533                 duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, reg_target + 1);  /* default instance */
68534                 DUK__SETTEMP(comp_ctx, reg_target + 2);
68535
68536                 /* XXX: 'new obj.noSuch()' doesn't use GETPROPC now which
68537                  * makes the error message worse than for obj.noSuch().
68538                  */
68539
68540                 if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
68541                         /* 'new' MemberExpression Arguments */
68542                         DUK_DDD(DUK_DDDPRINT("new expression has argument list"));
68543                         duk__advance(comp_ctx);
68544                         nargs = duk__parse_arguments(comp_ctx, res);  /* parse args starting from "next temp", reg_target + 1 */
68545                         /* right paren eaten */
68546                 } else {
68547                         /* 'new' MemberExpression */
68548                         DUK_DDD(DUK_DDDPRINT("new expression has no argument list"));
68549                         nargs = 0;
68550                 }
68551
68552                 duk__emit_a_bc(comp_ctx,
68553                               DUK_OP_CALL0 | DUK_BC_CALL_FLAG_CONSTRUCT,
68554                               nargs /*num_args*/,
68555                               reg_target /*target*/);
68556
68557                 DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
68558
68559                 duk__ivalue_regconst(res, reg_target);
68560                 return;
68561         }
68562
68563         /* FUNCTION EXPRESSIONS */
68564
68565         case DUK_TOK_FUNCTION: {
68566                 /* Function expression.  Note that any statement beginning with 'function'
68567                  * is handled by the statement parser as a function declaration, or a
68568                  * non-standard function expression/statement (or a SyntaxError).  We only
68569                  * handle actual function expressions (occurring inside an expression) here.
68570                  *
68571                  * O(depth^2) parse count for inner functions is handled by recording a
68572                  * lexer offset on the first compilation pass, so that the function can
68573                  * be efficiently skipped on the second pass.  This is encapsulated into
68574                  * duk__parse_func_like_fnum().
68575                  */
68576
68577                 duk_regconst_t reg_temp;
68578                 duk_int_t fnum;
68579
68580                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
68581
68582                 /* curr_token follows 'function' */
68583                 fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*flags*/);
68584                 DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum));
68585
68586                 duk__emit_a_bc(comp_ctx,
68587                                DUK_OP_CLOSURE,
68588                                reg_temp /*a*/,
68589                                (duk_regconst_t) fnum /*bc*/);
68590
68591                 duk__ivalue_regconst(res, reg_temp);
68592                 return;
68593         }
68594
68595         /* UNARY EXPRESSIONS */
68596
68597         case DUK_TOK_DELETE: {
68598                 /* Delete semantics are a bit tricky.  The description in E5 specification
68599                  * is kind of confusing, because it distinguishes between resolvability of
68600                  * a reference (which is only known at runtime) seemingly at compile time
68601                  * (= SyntaxError throwing).
68602                  */
68603                 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
68604                 if (res->t == DUK_IVAL_VAR) {
68605                         /* not allowed in strict mode, regardless of whether resolves;
68606                          * in non-strict mode DELVAR handles both non-resolving and
68607                          * resolving cases (the specification description is a bit confusing).
68608                          */
68609
68610                         duk_regconst_t reg_temp;
68611                         duk_regconst_t reg_varbind;
68612                         duk_regconst_t rc_varname;
68613
68614                         if (comp_ctx->curr_func.is_strict) {
68615                                 DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER);
68616                                 DUK_WO_NORETURN(return;);
68617                         }
68618
68619                         DUK__SETTEMP(comp_ctx, temp_at_entry);
68620                         reg_temp = DUK__ALLOCTEMP(comp_ctx);
68621
68622                         duk_dup(thr, res->x1.valstack_idx);
68623                         if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
68624                                 /* register bound variables are non-configurable -> always false */
68625                                 duk__emit_bc(comp_ctx,
68626                                              DUK_OP_LDFALSE,
68627                                              reg_temp);
68628                         } else {
68629                                 duk_dup(thr, res->x1.valstack_idx);
68630                                 rc_varname = duk__getconst(comp_ctx);
68631                                 duk__emit_a_bc(comp_ctx,
68632                                                DUK_OP_DELVAR,
68633                                                reg_temp,
68634                                                rc_varname);
68635                         }
68636                         duk__ivalue_regconst(res, reg_temp);
68637                 } else if (res->t == DUK_IVAL_PROP) {
68638                         duk_regconst_t reg_temp;
68639                         duk_regconst_t reg_obj;
68640                         duk_regconst_t rc_key;
68641
68642                         DUK__SETTEMP(comp_ctx, temp_at_entry);
68643                         reg_temp = DUK__ALLOCTEMP(comp_ctx);
68644                         reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
68645                         rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
68646                         duk__emit_a_b_c(comp_ctx,
68647                                         DUK_OP_DELPROP | DUK__EMIT_FLAG_BC_REGCONST,
68648                                         reg_temp,
68649                                         reg_obj,
68650                                         rc_key);
68651
68652                         duk__ivalue_regconst(res, reg_temp);
68653                 } else {
68654                         /* non-Reference deletion is always 'true', even in strict mode */
68655                         duk_push_true(thr);
68656                         goto plain_value;
68657                 }
68658                 return;
68659         }
68660         case DUK_TOK_VOID: {
68661                 duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
68662                 duk_push_undefined(thr);
68663                 goto plain_value;
68664         }
68665         case DUK_TOK_TYPEOF: {
68666                 /* 'typeof' must handle unresolvable references without throwing
68667                  * a ReferenceError (E5 Section 11.4.3).  Register mapped values
68668                  * will never be unresolvable so special handling is only required
68669                  * when an identifier is a "slow path" one.
68670                  */
68671                 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
68672
68673                 if (res->t == DUK_IVAL_VAR) {
68674                         duk_regconst_t reg_varbind;
68675                         duk_regconst_t rc_varname;
68676                         duk_regconst_t reg_temp;
68677
68678                         duk_dup(thr, res->x1.valstack_idx);
68679                         if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
68680                                 DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
68681                                                      "at compile time, need to use special run-time handling"));
68682                                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
68683                                 duk__emit_a_bc(comp_ctx,
68684                                                DUK_OP_TYPEOFID,
68685                                                reg_temp,
68686                                                rc_varname);
68687                                 duk__ivalue_regconst(res, reg_temp);
68688                                 return;
68689                         }
68690                 }
68691
68692                 args = DUK_OP_TYPEOF;
68693                 goto unary;
68694         }
68695         case DUK_TOK_INCREMENT: {
68696                 args = (DUK_OP_PREINCP << 8) + DUK_OP_PREINCR;
68697                 goto preincdec;
68698         }
68699         case DUK_TOK_DECREMENT: {
68700                 args = (DUK_OP_PREDECP << 8) + DUK_OP_PREDECR;
68701                 goto preincdec;
68702         }
68703         case DUK_TOK_ADD: {
68704                 /* unary plus */
68705                 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
68706                 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
68707                     duk_is_number(thr, res->x1.valstack_idx)) {
68708                         /* unary plus of a number is identity */
68709                         return;
68710                 }
68711                 args = DUK_OP_UNP;
68712                 goto unary;
68713         }
68714         case DUK_TOK_SUB: {
68715                 /* unary minus */
68716                 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
68717                 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
68718                     duk_is_number(thr, res->x1.valstack_idx)) {
68719                         /* this optimization is important to handle negative literals
68720                          * (which are not directly provided by the lexical grammar)
68721                          */
68722                         duk_tval *tv_num;
68723                         duk_double_union du;
68724
68725                         tv_num = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx);
68726                         DUK_ASSERT(tv_num != NULL);
68727                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
68728                         du.d = DUK_TVAL_GET_NUMBER(tv_num);
68729                         du.d = -du.d;
68730                         DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
68731                         DUK_TVAL_SET_NUMBER(tv_num, du.d);
68732                         return;
68733                 }
68734                 args = DUK_OP_UNM;
68735                 goto unary;
68736         }
68737         case DUK_TOK_BNOT: {
68738                 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
68739                 args = DUK_OP_BNOT;
68740                 goto unary;
68741         }
68742         case DUK_TOK_LNOT: {
68743                 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
68744                 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) {
68745                         /* Very minimal inlining to handle common idioms '!0' and '!1',
68746                          * and also boolean arguments like '!false' and '!true'.
68747                          */
68748                         duk_tval *tv_val;
68749
68750                         tv_val = DUK_GET_TVAL_POSIDX(thr, res->x1.valstack_idx);
68751                         DUK_ASSERT(tv_val != NULL);
68752                         if (DUK_TVAL_IS_NUMBER(tv_val)) {
68753                                 duk_double_t d;
68754                                 d = DUK_TVAL_GET_NUMBER(tv_val);
68755                                 if (d == 0.0) {
68756                                         /* Matches both +0 and -0 on purpose. */
68757                                         DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true"));
68758                                         DUK_TVAL_SET_BOOLEAN_TRUE(tv_val);
68759                                         return;
68760                                 } else if (d == 1.0) {
68761                                         DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false"));
68762                                         DUK_TVAL_SET_BOOLEAN_FALSE(tv_val);
68763                                         return;
68764                                 }
68765                         } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
68766                                 duk_small_uint_t v;
68767                                 v = DUK_TVAL_GET_BOOLEAN(tv_val);
68768                                 DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v));
68769                                 DUK_ASSERT(v == 0 || v == 1);
68770                                 DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01);
68771                                 return;
68772                         }
68773                 }
68774                 args = DUK_OP_LNOT;
68775                 goto unary;
68776         }
68777
68778         }  /* end switch */
68779
68780         DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
68781         DUK_WO_NORETURN(return;);
68782
68783  unary:
68784         {
68785                 /* Unary opcodes use just the 'BC' register source because it
68786                  * matches current shuffle limits, and maps cleanly to 16 high
68787                  * bits of the opcode.
68788                  */
68789
68790                 duk_regconst_t reg_src, reg_res;
68791
68792                 reg_src = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*flags*/);
68793                 if (DUK__ISREG_TEMP(comp_ctx, reg_src)) {
68794                         reg_res = reg_src;
68795                 } else {
68796                         reg_res = DUK__ALLOCTEMP(comp_ctx);
68797                 }
68798                 duk__emit_a_bc(comp_ctx,
68799                              args,
68800                              reg_res,
68801                              reg_src);
68802                 duk__ivalue_regconst(res, reg_res);
68803                 return;
68804         }
68805
68806  preincdec:
68807         {
68808                 /* preincrement and predecrement */
68809                 duk_regconst_t reg_res;
68810                 duk_small_uint_t args_op1 = args & 0xff;  /* DUK_OP_PREINCR/DUK_OP_PREDECR */
68811                 duk_small_uint_t args_op2 = args >> 8;    /* DUK_OP_PREINCP_RR/DUK_OP_PREDECP_RR */
68812
68813                 /* Specific assumptions for opcode numbering. */
68814                 DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV);
68815                 DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV);
68816
68817                 reg_res = DUK__ALLOCTEMP(comp_ctx);
68818
68819                 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/);  /* UnaryExpression */
68820                 if (res->t == DUK_IVAL_VAR) {
68821                         duk_hstring *h_varname;
68822                         duk_regconst_t reg_varbind;
68823                         duk_regconst_t rc_varname;
68824
68825                         h_varname = duk_known_hstring(thr, res->x1.valstack_idx);
68826
68827                         if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
68828                                 goto syntax_error;
68829                         }
68830
68831                         duk_dup(thr, res->x1.valstack_idx);
68832                         if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
68833                                 duk__emit_a_bc(comp_ctx,
68834                                                args_op1,  /* e.g. DUK_OP_PREINCR */
68835                                                reg_res,
68836                                                reg_varbind);
68837                         } else {
68838                                 duk__emit_a_bc(comp_ctx,
68839                                                 args_op1 + 4,  /* e.g. DUK_OP_PREINCV */
68840                                                 reg_res,
68841                                                 rc_varname);
68842                         }
68843
68844                         DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
68845                                              (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
68846                 } else if (res->t == DUK_IVAL_PROP) {
68847                         duk_regconst_t reg_obj;  /* allocate to reg only (not const) */
68848                         duk_regconst_t rc_key;
68849                         reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
68850                         rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
68851                         duk__emit_a_b_c(comp_ctx,
68852                                         args_op2 | DUK__EMIT_FLAG_BC_REGCONST,  /* e.g. DUK_OP_PREINCP */
68853                                         reg_res,
68854                                         reg_obj,
68855                                         rc_key);
68856                 } else {
68857                         /* Technically return value is not needed because INVLHS will
68858                          * unconditially throw a ReferenceError.  Coercion is necessary
68859                          * for proper semantics (consider ToNumber() called for an object).
68860                          * Use DUK_OP_UNP with a dummy register to get ToNumber().
68861                          */
68862
68863                         duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
68864                         duk__emit_bc(comp_ctx,
68865                                      DUK_OP_UNP,
68866                                      reg_res);  /* for side effects, result ignored */
68867                         duk__emit_op_only(comp_ctx,
68868                                           DUK_OP_INVLHS);
68869                 }
68870                 DUK__SETTEMP(comp_ctx, reg_res + 1);
68871                 duk__ivalue_regconst(res, reg_res);
68872                 return;
68873         }
68874
68875  plain_value:
68876         {
68877                 /* Stack top contains plain value */
68878                 duk__ivalue_plain_fromstack(comp_ctx, res);
68879                 return;
68880         }
68881
68882 #if defined(DUK_USE_ES6)
68883  syntax_error_newtarget:
68884         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_NEWTARGET);
68885         DUK_WO_NORETURN(return;);
68886 #endif
68887
68888  syntax_error:
68889         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
68890         DUK_WO_NORETURN(return;);
68891 }
68892
68893 /* XXX: add flag to indicate whether caller cares about return value; this
68894  * affects e.g. handling of assignment expressions.  This change needs API
68895  * changes elsewhere too.
68896  */
68897 DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
68898         duk_hthread *thr = comp_ctx->thr;
68899         duk_token *tk;
68900         duk_small_uint_t tok;
68901         duk_uint32_t args;  /* temp variable to pass constants and flags to shared code */
68902
68903         /*
68904          *  ctx->prev_token     token to process with duk__expr_led()
68905          *  ctx->curr_token     updated by caller
68906          */
68907
68908         comp_ctx->curr_func.led_count++;
68909
68910         /* The token in the switch has already been eaten here */
68911         tk = &comp_ctx->prev_token;
68912         tok = tk->t;
68913
68914         DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
68915                              (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
68916
68917         /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
68918
68919         switch (tok) {
68920
68921         /* PRIMARY EXPRESSIONS */
68922
68923         case DUK_TOK_PERIOD: {
68924                 /* Property access expressions are critical for correct LHS ordering,
68925                  * see comments in duk__expr()!
68926                  *
68927                  * A conservative approach would be to use duk__ivalue_totempconst()
68928                  * for 'left'.  However, allowing a reg-bound variable seems safe here
68929                  * and is nice because "foo.bar" is a common expression.  If the ivalue
68930                  * is used in an expression a GETPROP will occur before any changes to
68931                  * the base value can occur.  If the ivalue is used as an assignment
68932                  * LHS, the assignment code will ensure the base value is safe from
68933                  * RHS mutation.
68934                  */
68935
68936                 /* XXX: This now coerces an identifier into a GETVAR to a temp, which
68937                  * causes an extra LDREG in call setup.  It's sufficient to coerce to a
68938                  * unary ivalue?
68939                  */
68940                 duk__ivalue_toplain(comp_ctx, left);
68941
68942                 /* NB: must accept reserved words as property name */
68943                 if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) {
68944                         DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
68945                         DUK_WO_NORETURN(return;);
68946                 }
68947
68948                 res->t = DUK_IVAL_PROP;
68949                 duk__copy_ispec(comp_ctx, &left->x1, &res->x1);  /* left.x1 -> res.x1 */
68950                 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
68951                 duk_push_hstring(thr, comp_ctx->curr_token.str1);
68952                 duk_replace(thr, res->x2.valstack_idx);
68953                 res->x2.t = DUK_ISPEC_VALUE;
68954
68955                 /* special RegExp literal handling after IdentifierName */
68956                 comp_ctx->curr_func.reject_regexp_in_adv = 1;
68957
68958                 duk__advance(comp_ctx);
68959                 return;
68960         }
68961         case DUK_TOK_LBRACKET: {
68962                 /* Property access expressions are critical for correct LHS ordering,
68963                  * see comments in duk__expr()!
68964                  */
68965
68966                 /* XXX: optimize temp reg use */
68967                 /* XXX: similar coercion issue as in DUK_TOK_PERIOD */
68968                 /* XXX: coerce to regs? it might be better for enumeration use, where the
68969                  * same PROP ivalue is used multiple times.  Or perhaps coerce PROP further
68970                  * there?
68971                  */
68972                 /* XXX: for simple cases like x['y'] an unnecessary LDREG is
68973                  * emitted for the base value; could avoid it if we knew that
68974                  * the key expression is safe (e.g. just a single literal).
68975                  */
68976
68977                 /* The 'left' value must not be a register bound variable
68978                  * because it may be mutated during the rest of the expression
68979                  * and E5.1 Section 11.2.1 specifies the order of evaluation
68980                  * so that the base value is evaluated first.
68981                  * See: test-bug-nested-prop-mutate.js.
68982                  */
68983                 duk__ivalue_totempconst(comp_ctx, left);
68984                 duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);  /* Expression, ']' terminates */
68985                 duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
68986
68987                 res->t = DUK_IVAL_PROP;
68988                 duk__copy_ispec(comp_ctx, &res->x1, &res->x2);   /* res.x1 -> res.x2 */
68989                 duk__copy_ispec(comp_ctx, &left->x1, &res->x1);  /* left.x1 -> res.x1 */
68990                 return;
68991         }
68992         case DUK_TOK_LPAREN: {
68993                 /* function call */
68994                 duk_regconst_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
68995                 duk_int_t nargs;
68996                 duk_small_uint_t call_op = DUK_OP_CALL0;
68997
68998                 /* XXX: attempt to get the call result to "next temp" whenever
68999                  * possible to avoid unnecessary register shuffles.
69000                  */
69001
69002                 /*
69003                  *  Setup call: target and 'this' binding.  Three cases:
69004                  *
69005                  *    1. Identifier base (e.g. "foo()")
69006                  *    2. Property base (e.g. "foo.bar()")
69007                  *    3. Register base (e.g. "foo()()"; i.e. when a return value is a function)
69008                  */
69009
69010                 if (left->t == DUK_IVAL_VAR) {
69011                         duk_hstring *h_varname;
69012                         duk_regconst_t reg_varbind;
69013                         duk_regconst_t rc_varname;
69014
69015                         DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
69016
69017                         h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
69018                         if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
69019                                 /* Potential direct eval call detected, flag the CALL
69020                                  * so that a run-time "direct eval" check is made and
69021                                  * special behavior may be triggered.  Note that this
69022                                  * does not prevent 'eval' from being register bound.
69023                                  */
69024                                 DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
69025                                                      "-> using EVALCALL, marking function "
69026                                                      "as may_direct_eval"));
69027                                 call_op |= DUK_BC_CALL_FLAG_CALLED_AS_EVAL;
69028                                 comp_ctx->curr_func.may_direct_eval = 1;
69029                         }
69030
69031                         duk_dup(thr, left->x1.valstack_idx);
69032                         if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
69033                                 duk__emit_a_bc(comp_ctx,
69034                                               DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
69035                                               reg_varbind,
69036                                               reg_cs + 0);
69037                         } else {
69038                                 /* XXX: expand target register or constant field to
69039                                  * reduce shuffling.
69040                                  */
69041                                 DUK_ASSERT(DUK__ISCONST(rc_varname));
69042                                 duk__emit_a_b(comp_ctx,
69043                                               DUK_OP_CSVAR | DUK__EMIT_FLAG_BC_REGCONST,
69044                                               reg_cs + 0,
69045                                               rc_varname);
69046                         }
69047                 } else if (left->t == DUK_IVAL_PROP) {
69048                         /* Call through a property lookup, E5 Section 11.2.3, step 6.a.i,
69049                          * E5 Section 10.4.3.  There used to be a separate CSPROP opcode
69050                          * but a typical call setup took 3 opcodes (e.g. LDREG, LDCONST,
69051                          * CSPROP) and the same can be achieved with ordinary loads.
69052                          */
69053 #if defined(DUK_USE_VERBOSE_ERRORS)
69054                         duk_regconst_t reg_key;
69055 #endif
69056
69057                         DUK_DDD(DUK_DDDPRINT("function call with property base"));
69058
69059                         /* XXX: For Math.sin() this generates: LDCONST + LDREG +
69060                          * GETPROPC + call.  The LDREG is unnecessary because LDCONST
69061                          * could be loaded directly into reg_cs + 1.  This doesn't
69062                          * happen now because a variable cannot be in left->x1 of a
69063                          * DUK_IVAL_PROP.  We could notice that left->x1 is a temp
69064                          * and reuse, but it would still be in the wrong position
69065                          * (reg_cs + 0 rather than reg_cs + 1).
69066                          */
69067                         duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 1);  /* base */
69068 #if defined(DUK_USE_VERBOSE_ERRORS)
69069                         reg_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
69070                         duk__emit_a_b_c(comp_ctx,
69071                                         DUK_OP_GETPROPC | DUK__EMIT_FLAG_BC_REGCONST,
69072                                         reg_cs + 0,
69073                                         reg_cs + 1,
69074                                         reg_key);
69075 #else
69076                         duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);  /* base[key] */
69077 #endif
69078                 } else {
69079                         DUK_DDD(DUK_DDDPRINT("function call with register base"));
69080
69081                         duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
69082 #if 0
69083                         duk__emit_a_bc(comp_ctx,
69084                                        DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
69085                                        reg_cs + 0,
69086                                        reg_cs + 0);  /* in-place setup */
69087 #endif
69088                         /* Because of in-place setup, REGCS is equivalent to
69089                          * just this LDUNDEF.
69090                          */
69091                         duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, reg_cs + 1);
69092                 }
69093
69094                 DUK__SETTEMP(comp_ctx, reg_cs + 2);
69095                 nargs = duk__parse_arguments(comp_ctx, res);  /* parse args starting from "next temp" */
69096
69097                 /* Tailcalls are handled by back-patching the already emitted opcode
69098                  * later in return statement parser.
69099                  */
69100
69101                 duk__emit_a_bc(comp_ctx,
69102                                call_op,
69103                                (duk_regconst_t) nargs /*numargs*/,
69104                                reg_cs /*basereg*/);
69105                 DUK__SETTEMP(comp_ctx, reg_cs + 1);    /* result in csreg */
69106
69107                 duk__ivalue_regconst(res, reg_cs);
69108                 return;
69109         }
69110
69111         /* POSTFIX EXPRESSION */
69112
69113         case DUK_TOK_INCREMENT: {
69114                 args = (DUK_OP_POSTINCP_RR << 16) + (DUK_OP_POSTINCR << 8) + 0;
69115                 goto postincdec;
69116         }
69117         case DUK_TOK_DECREMENT: {
69118                 args = (DUK_OP_POSTDECP_RR << 16) + (DUK_OP_POSTDECR << 8) + 0;
69119                 goto postincdec;
69120         }
69121
69122         /* EXPONENTIATION EXPRESSION */
69123
69124 #if defined(DUK_USE_ES7_EXP_OPERATOR)
69125         case DUK_TOK_EXP: {
69126                 args = (DUK_OP_EXP << 8) + DUK__BP_EXPONENTIATION - 1;  /* UnaryExpression */
69127                 goto binary;
69128         }
69129 #endif
69130
69131         /* MULTIPLICATIVE EXPRESSION */
69132
69133         case DUK_TOK_MUL: {
69134                 args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE;  /* ExponentiationExpression */
69135                 goto binary;
69136         }
69137         case DUK_TOK_DIV: {
69138                 args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE;  /* ExponentiationExpression */
69139                 goto binary;
69140         }
69141         case DUK_TOK_MOD: {
69142                 args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE;  /* ExponentiationExpression */
69143                 goto binary;
69144         }
69145
69146         /* ADDITIVE EXPRESSION */
69147
69148         case DUK_TOK_ADD: {
69149                 args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE;  /* MultiplicativeExpression */
69150                 goto binary;
69151         }
69152         case DUK_TOK_SUB: {
69153                 args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE;  /* MultiplicativeExpression */
69154                 goto binary;
69155         }
69156
69157         /* SHIFT EXPRESSION */
69158
69159         case DUK_TOK_ALSHIFT: {
69160                 /* << */
69161                 args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT;
69162                 goto binary;
69163         }
69164         case DUK_TOK_ARSHIFT: {
69165                 /* >> */
69166                 args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT;
69167                 goto binary;
69168         }
69169         case DUK_TOK_RSHIFT: {
69170                 /* >>> */
69171                 args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT;
69172                 goto binary;
69173         }
69174
69175         /* RELATIONAL EXPRESSION */
69176
69177         case DUK_TOK_LT: {
69178                 /* < */
69179                 args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL;
69180                 goto binary;
69181         }
69182         case DUK_TOK_GT: {
69183                 args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL;
69184                 goto binary;
69185         }
69186         case DUK_TOK_LE: {
69187                 args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL;
69188                 goto binary;
69189         }
69190         case DUK_TOK_GE: {
69191                 args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL;
69192                 goto binary;
69193         }
69194         case DUK_TOK_INSTANCEOF: {
69195                 args = (DUK_OP_INSTOF << 8) + DUK__BP_RELATIONAL;
69196                 goto binary;
69197         }
69198         case DUK_TOK_IN: {
69199                 args = (DUK_OP_IN << 8) + DUK__BP_RELATIONAL;
69200                 goto binary;
69201         }
69202
69203         /* EQUALITY EXPRESSION */
69204
69205         case DUK_TOK_EQ: {
69206                 args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY;
69207                 goto binary;
69208         }
69209         case DUK_TOK_NEQ: {
69210                 args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY;
69211                 goto binary;
69212         }
69213         case DUK_TOK_SEQ: {
69214                 args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY;
69215                 goto binary;
69216         }
69217         case DUK_TOK_SNEQ: {
69218                 args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY;
69219                 goto binary;
69220         }
69221
69222         /* BITWISE EXPRESSIONS */
69223
69224         case DUK_TOK_BAND: {
69225                 args = (DUK_OP_BAND << 8) + DUK__BP_BAND;
69226                 goto binary;
69227         }
69228         case DUK_TOK_BXOR: {
69229                 args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR;
69230                 goto binary;
69231         }
69232         case DUK_TOK_BOR: {
69233                 args = (DUK_OP_BOR << 8) + DUK__BP_BOR;
69234                 goto binary;
69235         }
69236
69237         /* LOGICAL EXPRESSIONS */
69238
69239         case DUK_TOK_LAND: {
69240                 /* syntactically left-associative but parsed as right-associative */
69241                 args = (1 << 8) + DUK__BP_LAND - 1;
69242                 goto binary_logical;
69243         }
69244         case DUK_TOK_LOR: {
69245                 /* syntactically left-associative but parsed as right-associative */
69246                 args = (0 << 8) + DUK__BP_LOR - 1;
69247                 goto binary_logical;
69248         }
69249
69250         /* CONDITIONAL EXPRESSION */
69251
69252         case DUK_TOK_QUESTION: {
69253                 /* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
69254                  * but only if it really is a temp.  Nothing fancy here now.
69255                  */
69256                 duk_regconst_t reg_temp;
69257                 duk_int_t pc_jump1;
69258                 duk_int_t pc_jump2;
69259
69260                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
69261                 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
69262                 duk__emit_if_true_skip(comp_ctx, reg_temp);
69263                 pc_jump1 = duk__emit_jump_empty(comp_ctx);  /* jump to false */
69264                 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);  /* AssignmentExpression */
69265                 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
69266                 pc_jump2 = duk__emit_jump_empty(comp_ctx);  /* jump to end */
69267                 duk__patch_jump_here(comp_ctx, pc_jump1);
69268                 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);  /* AssignmentExpression */
69269                 duk__patch_jump_here(comp_ctx, pc_jump2);
69270
69271                 DUK__SETTEMP(comp_ctx, reg_temp + 1);
69272                 duk__ivalue_regconst(res, reg_temp);
69273                 return;
69274         }
69275
69276         /* ASSIGNMENT EXPRESSION */
69277
69278         case DUK_TOK_EQUALSIGN: {
69279                 /*
69280                  *  Assignments are right associative, allows e.g.
69281                  *    a = 5;
69282                  *    a += b = 9;   // same as a += (b = 9)
69283                  *  -> expression value 14, a = 14, b = 9
69284                  *
69285                  *  Right associativiness is reflected in the BP for recursion,
69286                  *  "-1" ensures assignment operations are allowed.
69287                  *
69288                  *  XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
69289                  */
69290                 args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1;   /* DUK_OP_NONE marks a 'plain' assignment */
69291                 goto assign;
69292         }
69293         case DUK_TOK_ADD_EQ: {
69294                 /* right associative */
69295                 args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1;
69296                 goto assign;
69297         }
69298         case DUK_TOK_SUB_EQ: {
69299                 /* right associative */
69300                 args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1;
69301                 goto assign;
69302         }
69303         case DUK_TOK_MUL_EQ: {
69304                 /* right associative */
69305                 args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1;
69306                 goto assign;
69307         }
69308         case DUK_TOK_DIV_EQ: {
69309                 /* right associative */
69310                 args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1;
69311                 goto assign;
69312         }
69313         case DUK_TOK_MOD_EQ: {
69314                 /* right associative */
69315                 args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
69316                 goto assign;
69317         }
69318 #if defined(DUK_USE_ES7_EXP_OPERATOR)
69319         case DUK_TOK_EXP_EQ: {
69320                 /* right associative */
69321                 args = (DUK_OP_EXP << 8) + DUK__BP_ASSIGNMENT - 1;
69322                 goto assign;
69323         }
69324 #endif
69325         case DUK_TOK_ALSHIFT_EQ: {
69326                 /* right associative */
69327                 args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
69328                 goto assign;
69329         }
69330         case DUK_TOK_ARSHIFT_EQ: {
69331                 /* right associative */
69332                 args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1;
69333                 goto assign;
69334         }
69335         case DUK_TOK_RSHIFT_EQ: {
69336                 /* right associative */
69337                 args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1;
69338                 goto assign;
69339         }
69340         case DUK_TOK_BAND_EQ: {
69341                 /* right associative */
69342                 args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1;
69343                 goto assign;
69344         }
69345         case DUK_TOK_BOR_EQ: {
69346                 /* right associative */
69347                 args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1;
69348                 goto assign;
69349         }
69350         case DUK_TOK_BXOR_EQ: {
69351                 /* right associative */
69352                 args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1;
69353                 goto assign;
69354         }
69355
69356         /* COMMA */
69357
69358         case DUK_TOK_COMMA: {
69359                 /* right associative */
69360
69361                 duk__ivalue_toplain_ignore(comp_ctx, left);  /* need side effects, not value */
69362                 duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/);
69363
69364                 /* return 'res' (of right part) as our result */
69365                 return;
69366         }
69367
69368         default: {
69369                 break;
69370         }
69371         }
69372
69373         DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok));
69374         DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
69375         DUK_WO_NORETURN(return;);
69376
69377 #if 0
69378         /* XXX: shared handling for 'duk__expr_lhs'? */
69379         if (comp_ctx->curr_func.paren_level == 0 && XXX) {
69380                 comp_ctx->curr_func.duk__expr_lhs = 0;
69381         }
69382 #endif
69383
69384  binary:
69385         /*
69386          *  Shared handling of binary operations
69387          *
69388          *  args = (opcode << 8) + rbp
69389          */
69390         {
69391                 duk__ivalue_toplain(comp_ctx, left);
69392                 duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/);
69393
69394                 /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */
69395                 DUK_ASSERT(left->t == DUK_IVAL_PLAIN);
69396                 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
69397
69398                 res->t = DUK_IVAL_ARITH;
69399                 res->op = (args >> 8) & 0xff;
69400
69401                 res->x2.t = res->x1.t;
69402                 res->x2.regconst = res->x1.regconst;
69403                 duk_copy(thr, res->x1.valstack_idx, res->x2.valstack_idx);
69404
69405                 res->x1.t = left->x1.t;
69406                 res->x1.regconst = left->x1.regconst;
69407                 duk_copy(thr, left->x1.valstack_idx, res->x1.valstack_idx);
69408
69409                 DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
69410                                      (long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst));
69411                 return;
69412         }
69413
69414  binary_logical:
69415         /*
69416          *  Shared handling for logical AND and logical OR.
69417          *
69418          *  args = (truthval << 8) + rbp
69419          *
69420          *  Truthval determines when to skip right-hand-side.
69421          *  For logical AND truthval=1, for logical OR truthval=0.
69422          *
69423          *  See doc/compiler.rst for discussion on compiling logical
69424          *  AND and OR expressions.  The approach here is very simplistic,
69425          *  generating extra jumps and multiple evaluations of truth values,
69426          *  but generates code on-the-fly with only local back-patching.
69427          *
69428          *  Both logical AND and OR are syntactically left-associated.
69429          *  However, logical ANDs are compiled as right associative
69430          *  expressions, i.e. "A && B && C" as "A && (B && C)", to allow
69431          *  skip jumps to skip over the entire tail.  Similarly for logical OR.
69432          */
69433
69434         {
69435                 duk_regconst_t reg_temp;
69436                 duk_int_t pc_jump;
69437                 duk_small_uint_t args_truthval = args >> 8;
69438                 duk_small_uint_t args_rbp = args & 0xff;
69439
69440                 /* XXX: unoptimal use of temps, resetting */
69441
69442                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
69443
69444                 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
69445                 DUK_ASSERT(DUK__ISREG(reg_temp));
69446                 duk__emit_bc(comp_ctx,
69447                             (args_truthval ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R),
69448                             reg_temp);  /* skip jump conditionally */
69449                 pc_jump = duk__emit_jump_empty(comp_ctx);
69450                 duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
69451                 duk__patch_jump_here(comp_ctx, pc_jump);
69452
69453                 duk__ivalue_regconst(res, reg_temp);
69454                 return;
69455         }
69456
69457  assign:
69458         /*
69459          *  Shared assignment expression handling
69460          *
69461          *  args = (opcode << 8) + rbp
69462          *
69463          *  If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic.
69464          *  Syntactically valid left-hand-side forms which are not accepted as
69465          *  left-hand-side values (e.g. as in "f() = 1") must NOT cause a
69466          *  SyntaxError, but rather a run-time ReferenceError.
69467          *
69468          *  When evaluating X <op>= Y, the LHS (X) is conceptually evaluated
69469          *  to a temporary first.  The RHS is then evaluated.  Finally, the
69470          *  <op> is applied to the initial value of RHS (not the value after
69471          *  RHS evaluation), and written to X.  Doing so concretely generates
69472          *  inefficient code so we'd like to avoid the temporary when possible.
69473          *  See: https://github.com/svaarala/duktape/pull/992.
69474          *
69475          *  The expression value (final LHS value, written to RHS) is
69476          *  conceptually copied into a fresh temporary so that it won't
69477          *  change even if the LHS/RHS values change in outer expressions.
69478          *  For example, it'd be generally incorrect for the expression value
69479          *  to be the RHS register binding, unless there's a guarantee that it
69480          *  won't change during further expression evaluation.  Using the
69481          *  temporary concretely produces inefficient bytecode, so we try to
69482          *  avoid the extra temporary for some known-to-be-safe cases.
69483          *  Currently the only safe case we detect is a "top level assignment",
69484          *  for example "x = y + z;", where the assignment expression value is
69485          *  ignored.
69486          *  See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
69487          */
69488
69489         {
69490                 duk_small_uint_t args_op = args >> 8;
69491                 duk_small_uint_t args_rbp = args & 0xff;
69492                 duk_bool_t toplevel_assign;
69493
69494                 /* XXX: here we need to know if 'left' is left-hand-side compatible.
69495                  * That information is no longer available from current expr parsing
69496                  * state; it would need to be carried into the 'left' ivalue or by
69497                  * some other means.
69498                  */
69499
69500                 /* A top-level assignment is e.g. "x = y;".  For these it's safe
69501                  * to use the RHS as-is as the expression value, even if the RHS
69502                  * is a reg-bound identifier.  The RHS ('res') is right associative
69503                  * so it has consumed all other assignment level operations; the
69504                  * only relevant lower binding power construct is comma operator
69505                  * which will ignore the expression value provided here.  Usually
69506                  * the top level assignment expression value is ignored, but it
69507                  * is relevant for e.g. eval code.
69508                  */
69509                 toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */
69510                                    comp_ctx->curr_func.led_count == 1);  /* one operator (= assign) */
69511                 DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld",
69512                                      (long) comp_ctx->curr_func.nud_count,
69513                                      (long) comp_ctx->curr_func.led_count,
69514                                      (long) toplevel_assign));
69515
69516                 if (left->t == DUK_IVAL_VAR) {
69517                         duk_hstring *h_varname;
69518                         duk_regconst_t reg_varbind;
69519                         duk_regconst_t rc_varname;
69520
69521                         DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE);  /* LHS is already side effect free */
69522
69523                         h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
69524                         if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
69525                                 /* E5 Section 11.13.1 (and others for other assignments), step 4. */
69526                                 goto syntax_error_lvalue;
69527                         }
69528                         duk_dup(thr, left->x1.valstack_idx);
69529                         (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
69530
69531                         if (args_op == DUK_OP_NONE) {
69532                                 duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
69533                                 if (toplevel_assign) {
69534                                         /* Any 'res' will do. */
69535                                         DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
69536                                 } else {
69537                                         /* 'res' must be a plain ivalue, and not register-bound variable. */
69538                                         DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
69539                                         if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST &&
69540                                                                          DUK__ISREG_NOTTEMP(comp_ctx, res->x1.regconst))) {
69541                                                 duk__ivalue_totempconst(comp_ctx, res);
69542                                         }
69543                                 }
69544                         } else {
69545                                 /* For X <op>= Y we need to evaluate the pre-op
69546                                  * value of X before evaluating the RHS: the RHS
69547                                  * can change X, but when we do <op> we must use
69548                                  * the pre-op value.
69549                                  */
69550                                 duk_regconst_t reg_temp;
69551
69552                                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
69553
69554                                 if (reg_varbind >= 0) {
69555                                         duk_regconst_t reg_res;
69556                                         duk_regconst_t reg_src;
69557                                         duk_int_t pc_temp_load;
69558                                         duk_int_t pc_before_rhs;
69559                                         duk_int_t pc_after_rhs;
69560
69561                                         if (toplevel_assign) {
69562                                                 /* 'reg_varbind' is the operation result and can also
69563                                                  * become the expression value for top level assignments
69564                                                  * such as: "var x; x += y;".
69565                                                  */
69566                                                 DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind"));
69567                                                 reg_res = reg_varbind;
69568                                         } else {
69569                                                 /* Not safe to use 'reg_varbind' as assignment expression
69570                                                  * value, so go through a temp.
69571                                                  */
69572                                                 DUK_DD(DUK_DDPRINT("<op>= expression is not top level, write to reg_temp"));
69573                                                 reg_res = reg_temp;  /* reg_res should be smallest possible */
69574                                                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
69575                                         }
69576
69577                                         /* Try to optimize X <op>= Y for reg-bound
69578                                          * variables.  Detect side-effect free RHS
69579                                          * narrowly by seeing whether it emits code.
69580                                          * If not, rewind the code emitter and overwrite
69581                                          * the unnecessary temp reg load.
69582                                          */
69583
69584                                         pc_temp_load = duk__get_current_pc(comp_ctx);
69585                                         duk__emit_a_bc(comp_ctx,
69586                                                        DUK_OP_LDREG,
69587                                                        reg_temp,
69588                                                        reg_varbind);
69589
69590                                         pc_before_rhs = duk__get_current_pc(comp_ctx);
69591                                         duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
69592                                         DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
69593                                         pc_after_rhs = duk__get_current_pc(comp_ctx);
69594
69595                                         DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld",
69596                                                            (long) pc_temp_load, (long) pc_before_rhs,
69597                                                            (long) pc_after_rhs));
69598
69599                                         if (pc_after_rhs == pc_before_rhs) {
69600                                                 /* Note: if the reg_temp load generated shuffling
69601                                                  * instructions, we may need to rewind more than
69602                                                  * one instruction, so use explicit PC computation.
69603                                                  */
69604                                                 DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
69605                                                 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));
69606                                                 reg_src = reg_varbind;
69607                                         } else {
69608                                                 DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
69609                                                 reg_src = reg_temp;
69610                                         }
69611
69612                                         duk__emit_a_b_c(comp_ctx,
69613                                                         args_op | DUK__EMIT_FLAG_BC_REGCONST,
69614                                                         reg_res,
69615                                                         reg_src,
69616                                                         res->x1.regconst);
69617
69618                                         res->x1.regconst = reg_res;
69619
69620                                         /* Ensure compact use of temps. */
69621                                         if (DUK__ISREG_TEMP(comp_ctx, reg_res)) {
69622                                                 DUK__SETTEMP(comp_ctx, reg_res + 1);
69623                                         }
69624                                 } else {
69625                                         /* When LHS is not register bound, always go through a
69626                                          * temporary.  No optimization for top level assignment.
69627                                          */
69628
69629                                         duk__emit_a_bc(comp_ctx,
69630                                                        DUK_OP_GETVAR,
69631                                                        reg_temp,
69632                                                        rc_varname);
69633
69634                                         duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
69635                                         DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
69636
69637                                         duk__emit_a_b_c(comp_ctx,
69638                                                         args_op | DUK__EMIT_FLAG_BC_REGCONST,
69639                                                         reg_temp,
69640                                                         reg_temp,
69641                                                         res->x1.regconst);
69642                                         res->x1.regconst = reg_temp;
69643                                 }
69644
69645                                 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
69646                         }
69647
69648                         /* At this point 'res' holds the potential expression value.
69649                          * It can be basically any ivalue here, including a reg-bound
69650                          * identifier (if code above deems it safe) or a unary/binary
69651                          * operation.  Operations must be resolved to a side effect free
69652                          * plain value, and the side effects must happen exactly once.
69653                          */
69654
69655                         if (reg_varbind >= 0) {
69656                                 if (res->t != DUK_IVAL_PLAIN) {
69657                                         /* Resolve 'res' directly into the LHS binding, and use
69658                                          * that as the expression value if safe.  If not safe,
69659                                          * resolve to a temp/const and copy to LHS.
69660                                          */
69661                                         if (toplevel_assign) {
69662                                                 duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind);
69663                                         } else {
69664                                                 duk__ivalue_totempconst(comp_ctx, res);
69665                                                 duk__copy_ivalue(comp_ctx, res, left);  /* use 'left' as a temp */
69666                                                 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
69667                                         }
69668                                 } else {
69669                                         /* Use 'res' as the expression value (it's side effect
69670                                          * free and may be a plain value, a register, or a
69671                                          * constant) and write it to the LHS binding too.
69672                                          */
69673                                         duk__copy_ivalue(comp_ctx, res, left);  /* use 'left' as a temp */
69674                                         duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
69675                                 }
69676                         } else {
69677                                 /* Only a reg fits into 'A' so coerce 'res' into a register
69678                                  * for PUTVAR.
69679                                  *
69680                                  * XXX: here the current A/B/C split is suboptimal: we could
69681                                  * just use 9 bits for reg_res (and support constants) and 17
69682                                  * instead of 18 bits for the varname const index.
69683                                  */
69684
69685                                 duk__ivalue_toreg(comp_ctx, res);
69686                                 duk__emit_a_bc(comp_ctx,
69687                                                DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
69688                                                res->x1.regconst,
69689                                                rc_varname);
69690                         }
69691
69692                         /* 'res' contains expression value */
69693                 } else if (left->t == DUK_IVAL_PROP) {
69694                         /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
69695                         duk_regconst_t reg_obj;
69696                         duk_regconst_t rc_key;
69697                         duk_regconst_t rc_res;
69698                         duk_regconst_t reg_temp;
69699
69700                         /* Property access expressions ('a[b]') are critical to correct
69701                          * LHS evaluation ordering, see test-dev-assign-eval-order*.js.
69702                          * We must make sure that the LHS target slot (base object and
69703                          * key) don't change during RHS evaluation.  The only concrete
69704                          * problem is a register reference to a variable-bound register
69705                          * (i.e., non-temp).  Require temp regs for both key and base.
69706                          *
69707                          * Don't allow a constant for the object (even for a number
69708                          * etc), as it goes into the 'A' field of the opcode.
69709                          */
69710
69711                         reg_obj = duk__ispec_toregconst_raw(comp_ctx,
69712                                                             &left->x1,
69713                                                             -1 /*forced_reg*/,
69714                                                             DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
69715
69716                         rc_key = duk__ispec_toregconst_raw(comp_ctx,
69717                                                            &left->x2,
69718                                                            -1 /*forced_reg*/,
69719                                                            DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
69720
69721                         /* Evaluate RHS only when LHS is safe. */
69722
69723                         if (args_op == DUK_OP_NONE) {
69724                                 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
69725                                 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
69726                                 rc_res = res->x1.regconst;
69727                         } else {
69728                                 reg_temp = DUK__ALLOCTEMP(comp_ctx);
69729                                 duk__emit_a_b_c(comp_ctx,
69730                                                 DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
69731                                                 reg_temp,
69732                                                 reg_obj,
69733                                                 rc_key);
69734
69735                                 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
69736                                 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
69737
69738                                 duk__emit_a_b_c(comp_ctx,
69739                                                 args_op | DUK__EMIT_FLAG_BC_REGCONST,
69740                                                 reg_temp,
69741                                                 reg_temp,
69742                                                 res->x1.regconst);
69743                                 rc_res = reg_temp;
69744                         }
69745
69746                         duk__emit_a_b_c(comp_ctx,
69747                                         DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
69748                                         reg_obj,
69749                                         rc_key,
69750                                         rc_res);
69751
69752                         duk__ivalue_regconst(res, rc_res);
69753                 } else {
69754                         /* No support for lvalues returned from new or function call expressions.
69755                          * However, these must NOT cause compile-time SyntaxErrors, but run-time
69756                          * ReferenceErrors.  Both left and right sides of the assignment must be
69757                          * evaluated before throwing a ReferenceError.  For instance:
69758                          *
69759                          *     f() = g();
69760                          *
69761                          * must result in f() being evaluated, then g() being evaluated, and
69762                          * finally, a ReferenceError being thrown.  See E5 Section 11.13.1.
69763                          */
69764
69765                         duk_regconst_t rc_res;
69766
69767                         /* First evaluate LHS fully to ensure all side effects are out. */
69768                         duk__ivalue_toplain_ignore(comp_ctx, left);
69769
69770                         /* Then evaluate RHS fully (its value becomes the expression value too).
69771                          * Technically we'd need the side effect safety check here too, but because
69772                          * we always throw using INVLHS the result doesn't matter.
69773                          */
69774                         rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
69775
69776                         duk__emit_op_only(comp_ctx, DUK_OP_INVLHS);
69777
69778                         duk__ivalue_regconst(res, rc_res);
69779                 }
69780
69781                 return;
69782         }
69783
69784  postincdec:
69785         {
69786                 /*
69787                  *  Post-increment/decrement will return the original value as its
69788                  *  result value.  However, even that value will be coerced using
69789                  *  ToNumber() which is quite awkward.  Specific bytecode opcodes
69790                  *  are used to handle these semantics.
69791                  *
69792                  *  Note that post increment/decrement has a "no LineTerminator here"
69793                  *  restriction.  This is handled by duk__expr_lbp(), which forcibly terminates
69794                  *  the previous expression if a LineTerminator occurs before '++'/'--'.
69795                  */
69796
69797                 duk_regconst_t reg_res;
69798                 duk_small_uint_t args_op1 = (args >> 8) & 0xff;  /* DUK_OP_POSTINCR/DUK_OP_POSTDECR */
69799                 duk_small_uint_t args_op2 = args >> 16;          /* DUK_OP_POSTINCP_RR/DUK_OP_POSTDECP_RR */
69800
69801                 /* Specific assumptions for opcode numbering. */
69802                 DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV);
69803                 DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV);
69804
69805                 reg_res = DUK__ALLOCTEMP(comp_ctx);
69806
69807                 if (left->t == DUK_IVAL_VAR) {
69808                         duk_hstring *h_varname;
69809                         duk_regconst_t reg_varbind;
69810                         duk_regconst_t rc_varname;
69811
69812                         h_varname = duk_known_hstring(thr, left->x1.valstack_idx);
69813
69814                         if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
69815                                 goto syntax_error;
69816                         }
69817
69818                         duk_dup(thr, left->x1.valstack_idx);
69819                         if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
69820                                 duk__emit_a_bc(comp_ctx,
69821                                                args_op1,  /* e.g. DUK_OP_POSTINCR */
69822                                                reg_res,
69823                                                reg_varbind);
69824                         } else {
69825                                 duk__emit_a_bc(comp_ctx,
69826                                                args_op1 + 4,  /* e.g. DUK_OP_POSTINCV */
69827                                                reg_res,
69828                                                rc_varname);
69829                         }
69830
69831                         DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
69832                                              (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
69833                 } else if (left->t == DUK_IVAL_PROP) {
69834                         duk_regconst_t reg_obj;  /* allocate to reg only (not const) */
69835                         duk_regconst_t rc_key;
69836
69837                         reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
69838                         rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
69839                         duk__emit_a_b_c(comp_ctx,
69840                                         args_op2 | DUK__EMIT_FLAG_BC_REGCONST,  /* e.g. DUK_OP_POSTINCP */
69841                                         reg_res,
69842                                         reg_obj,
69843                                         rc_key);
69844                 } else {
69845                         /* Technically return value is not needed because INVLHS will
69846                          * unconditially throw a ReferenceError.  Coercion is necessary
69847                          * for proper semantics (consider ToNumber() called for an object).
69848                          * Use DUK_OP_UNP with a dummy register to get ToNumber().
69849                          */
69850                         duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
69851                         duk__emit_bc(comp_ctx,
69852                                      DUK_OP_UNP,
69853                                      reg_res);  /* for side effects, result ignored */
69854                         duk__emit_op_only(comp_ctx,
69855                                           DUK_OP_INVLHS);
69856                 }
69857
69858                 DUK__SETTEMP(comp_ctx, reg_res + 1);
69859                 duk__ivalue_regconst(res, reg_res);
69860                 return;
69861         }
69862
69863  syntax_error:
69864         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
69865         DUK_WO_NORETURN(return;);
69866
69867  syntax_error_lvalue:
69868         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE);
69869         DUK_WO_NORETURN(return;);
69870 }
69871
69872 DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
69873         duk_small_uint_t tok = comp_ctx->curr_token.t;
69874
69875         DUK_ASSERT_DISABLE(tok >= DUK_TOK_MINVAL);  /* unsigned */
69876         DUK_ASSERT(tok <= DUK_TOK_MAXVAL);
69877         DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
69878
69879         /* XXX: integrate support for this into led() instead?
69880          * Similar issue as post-increment/post-decrement.
69881          */
69882
69883         /* prevent duk__expr_led() by using a binding power less than anything valid */
69884         if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) {
69885                 return 0;
69886         }
69887
69888         if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) &&
69889             (comp_ctx->curr_token.lineterm)) {
69890                 /* '++' or '--' in a post-increment/decrement position,
69891                  * and a LineTerminator occurs between the operator and
69892                  * the preceding expression.  Force the previous expr
69893                  * to terminate, in effect treating e.g. "a,b\n++" as
69894                  * "a,b;++" (= SyntaxError).
69895                  */
69896                 return 0;
69897         }
69898
69899         return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]);  /* format is bit packed */
69900 }
69901
69902 /*
69903  *  Expression parsing.
69904  *
69905  *  Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the
69906  *  first token of the expression.  Upon exit, 'curr_tok' will be the first
69907  *  token not part of the expression (e.g. semicolon terminating an expression
69908  *  statement).
69909  */
69910
69911 #define DUK__EXPR_RBP_MASK           0xff
69912 #define DUK__EXPR_FLAG_REJECT_IN     (1 << 8)   /* reject 'in' token (used for for-in) */
69913 #define DUK__EXPR_FLAG_ALLOW_EMPTY   (1 << 9)   /* allow empty expression */
69914 #define DUK__EXPR_FLAG_REQUIRE_INIT  (1 << 10)  /* require initializer for var/const */
69915
69916 /* main expression parser function */
69917 DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
69918         duk_hthread *thr = comp_ctx->thr;
69919         duk_ivalue tmp_alloc;   /* 'res' is used for "left", and 'tmp' for "right" */
69920         duk_ivalue *tmp = &tmp_alloc;
69921         duk_small_uint_t rbp;
69922
69923         DUK__RECURSION_INCREASE(comp_ctx, thr);
69924
69925         duk_require_stack(thr, DUK__PARSE_EXPR_SLOTS);
69926
69927         /* filter out flags from exprtop rbp_flags here to save space */
69928         rbp = rbp_flags & DUK__EXPR_RBP_MASK;
69929
69930         DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld",
69931                              (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in,
69932                              (long) comp_ctx->curr_func.paren_level));
69933
69934         duk_memzero(&tmp_alloc, sizeof(tmp_alloc));
69935         tmp->x1.valstack_idx = duk_get_top(thr);
69936         tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
69937         duk_push_undefined(thr);
69938         duk_push_undefined(thr);
69939
69940         /* XXX: where to release temp regs in intermediate expressions?
69941          * e.g. 1+2+3 -> don't inflate temp register count when parsing this.
69942          * that particular expression temp regs can be forced here.
69943          */
69944
69945         /* XXX: increase ctx->expr_tokens here for every consumed token
69946          * (this would be a nice statistic)?
69947          */
69948
69949         if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
69950                 /* XXX: possibly incorrect handling of empty expression */
69951                 DUK_DDD(DUK_DDDPRINT("empty expression"));
69952                 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
69953                         DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
69954                         DUK_WO_NORETURN(return;);
69955                 }
69956                 duk_push_undefined(thr);
69957                 duk__ivalue_plain_fromstack(comp_ctx, res);
69958                 goto cleanup;
69959         }
69960
69961         duk__advance(comp_ctx);
69962         duk__expr_nud(comp_ctx, res);  /* reuse 'res' as 'left' */
69963         while (rbp < duk__expr_lbp(comp_ctx)) {
69964                 duk__advance(comp_ctx);
69965                 duk__expr_led(comp_ctx, res, tmp);
69966                 duk__copy_ivalue(comp_ctx, tmp, res);  /* tmp -> res */
69967         }
69968
69969  cleanup:
69970         /* final result is already in 'res' */
69971
69972         duk_pop_2(thr);
69973
69974         DUK__RECURSION_DECREASE(comp_ctx, thr);
69975 }
69976
69977 DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
69978         duk_hthread *thr = comp_ctx->thr;
69979
69980         /* Note: these variables must reside in 'curr_func' instead of the global
69981          * context: when parsing function expressions, expression parsing is nested.
69982          */
69983         comp_ctx->curr_func.nud_count = 0;
69984         comp_ctx->curr_func.led_count = 0;
69985         comp_ctx->curr_func.paren_level = 0;
69986         comp_ctx->curr_func.expr_lhs = 1;
69987         comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1);
69988
69989         duk__expr(comp_ctx, res, rbp_flags);
69990
69991         if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) {
69992                 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
69993                 DUK_WO_NORETURN(return;);
69994         }
69995 }
69996
69997 /* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
69998  * and result conversions.
69999  *
70000  * Each helper needs at least 2-3 calls to make it worth while to wrap.
70001  */
70002
70003 #if 0  /* unused */
70004 DUK_LOCAL duk_regconst_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70005         duk__expr(comp_ctx, res, rbp_flags);
70006         return duk__ivalue_toreg(comp_ctx, res);
70007 }
70008 #endif
70009
70010 #if 0  /* unused */
70011 DUK_LOCAL duk_regconst_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70012         duk__expr(comp_ctx, res, rbp_flags);
70013         return duk__ivalue_totemp(comp_ctx, res);
70014 }
70015 #endif
70016
70017 DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) {
70018         DUK_ASSERT(forced_reg >= 0);
70019         duk__expr(comp_ctx, res, rbp_flags);
70020         duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
70021 }
70022
70023 DUK_LOCAL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70024         duk__expr(comp_ctx, res, rbp_flags);
70025         return duk__ivalue_toregconst(comp_ctx, res);
70026 }
70027
70028 #if 0  /* unused */
70029 DUK_LOCAL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70030         duk__expr(comp_ctx, res, rbp_flags);
70031         return duk__ivalue_totempconst(comp_ctx, res);
70032 }
70033 #endif
70034
70035 DUK_LOCAL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70036         duk__expr(comp_ctx, res, rbp_flags);
70037         duk__ivalue_toplain(comp_ctx, res);
70038 }
70039
70040 DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70041         duk__expr(comp_ctx, res, rbp_flags);
70042         duk__ivalue_toplain_ignore(comp_ctx, res);
70043 }
70044
70045 DUK_LOCAL duk_regconst_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70046         duk__exprtop(comp_ctx, res, rbp_flags);
70047         return duk__ivalue_toreg(comp_ctx, res);
70048 }
70049
70050 #if 0  /* unused */
70051 DUK_LOCAL duk_regconst_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70052         duk__exprtop(comp_ctx, res, rbp_flags);
70053         return duk__ivalue_totemp(comp_ctx, res);
70054 }
70055 #endif
70056
70057 DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_regconst_t forced_reg) {
70058         DUK_ASSERT(forced_reg >= 0);
70059         duk__exprtop(comp_ctx, res, rbp_flags);
70060         duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
70061 }
70062
70063 DUK_LOCAL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
70064         duk__exprtop(comp_ctx, res, rbp_flags);
70065         return duk__ivalue_toregconst(comp_ctx, res);
70066 }
70067
70068 #if 0  /* unused */
70069 DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
70070         duk__exprtop(comp_ctx, res, rbp_flags);
70071         duk__ivalue_toplain_ignore(comp_ctx, res);
70072 }
70073 #endif
70074
70075 /*
70076  *  Parse an individual source element (top level statement) or a statement.
70077  *
70078  *  Handles labeled statements automatically (peeling away labels before
70079  *  parsing an expression that follows the label(s)).
70080  *
70081  *  Upon entry, 'curr_tok' contains the first token of the statement (parsed
70082  *  in "allow regexp literal" mode).  Upon exit, 'curr_tok' contains the first
70083  *  token following the statement (if the statement has a terminator, this is
70084  *  the token after the terminator).
70085  */
70086
70087 #define DUK__HAS_VAL                  (1 << 0)  /* stmt has non-empty value */
70088 #define DUK__HAS_TERM                 (1 << 1)  /* stmt has explicit/implicit semicolon terminator */
70089 #define DUK__ALLOW_AUTO_SEMI_ALWAYS   (1 << 2)  /* allow automatic semicolon even without lineterm (compatibility) */
70090 #define DUK__STILL_PROLOGUE           (1 << 3)  /* statement does not terminate directive prologue */
70091 #define DUK__IS_TERMINAL              (1 << 4)  /* statement is guaranteed to be terminal (control doesn't flow to next statement) */
70092
70093 /* Parse a single variable declaration (e.g. "i" or "i=10").  A leading 'var'
70094  * has already been eaten.  These is no return value in 'res', it is used only
70095  * as a temporary.
70096  *
70097  * When called from 'for-in' statement parser, the initializer expression must
70098  * not allow the 'in' token.  The caller supply additional expression parsing
70099  * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'.
70100  *
70101  * Finally, out_rc_varname and out_reg_varbind are updated to reflect where
70102  * the identifier is bound:
70103  *
70104  *    If register bound:      out_reg_varbind >= 0, out_rc_varname == 0 (ignore)
70105  *    If not register bound:  out_reg_varbind < 0, out_rc_varname >= 0
70106  *
70107  * These allow the caller to use the variable for further assignment, e.g.
70108  * as is done in 'for-in' parsing.
70109  */
70110
70111 DUK_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) {
70112         duk_hthread *thr = comp_ctx->thr;
70113         duk_hstring *h_varname;
70114         duk_regconst_t reg_varbind;
70115         duk_regconst_t rc_varname;
70116
70117         /* assume 'var' has been eaten */
70118
70119         /* Note: Identifier rejects reserved words */
70120         if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
70121                 goto syntax_error;
70122         }
70123         h_varname = comp_ctx->curr_token.str1;
70124
70125         DUK_ASSERT(h_varname != NULL);
70126
70127         /* strict mode restrictions (E5 Section 12.2.1) */
70128         if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
70129                 goto syntax_error;
70130         }
70131
70132         /* register declarations in first pass */
70133         if (comp_ctx->curr_func.in_scanning) {
70134                 duk_uarridx_t n;
70135                 DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
70136                                      (duk_heaphdr *) h_varname));
70137                 n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
70138                 duk_push_hstring(thr, h_varname);
70139                 duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n);
70140                 duk_push_int(thr, DUK_DECL_TYPE_VAR + (0 << 8));
70141                 duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1);
70142         }
70143
70144         duk_push_hstring(thr, h_varname);  /* push before advancing to keep reachable */
70145
70146         /* register binding lookup is based on varmap (even in first pass) */
70147         duk_dup_top(thr);
70148         (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
70149
70150         duk__advance(comp_ctx);  /* eat identifier */
70151
70152         if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) {
70153                 duk__advance(comp_ctx);
70154
70155                 DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
70156                                      (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
70157
70158                 duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/);  /* AssignmentExpression */
70159
70160                 if (reg_varbind >= 0) {
70161                         duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
70162                 } else {
70163                         duk_regconst_t reg_val;
70164                         reg_val = duk__ivalue_toreg(comp_ctx, res);
70165                         duk__emit_a_bc(comp_ctx,
70166                                        DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
70167                                        reg_val,
70168                                        rc_varname);
70169                 }
70170         } else {
70171                 if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) {
70172                         /* Used for minimal 'const': initializer required. */
70173                         goto syntax_error;
70174                 }
70175         }
70176
70177         duk_pop(thr);  /* pop varname */
70178
70179         *out_rc_varname = rc_varname;
70180         *out_reg_varbind = reg_varbind;
70181
70182         return;
70183
70184  syntax_error:
70185         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION);
70186         DUK_WO_NORETURN(return;);
70187 }
70188
70189 DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) {
70190         duk_regconst_t reg_varbind;
70191         duk_regconst_t rc_varname;
70192
70193         duk__advance(comp_ctx);  /* eat 'var' */
70194
70195         for (;;) {
70196                 /* rc_varname and reg_varbind are ignored here */
70197                 duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, &reg_varbind, &rc_varname);
70198
70199                 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
70200                         break;
70201                 }
70202                 duk__advance(comp_ctx);
70203         }
70204 }
70205
70206 DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
70207         duk_hthread *thr = comp_ctx->thr;
70208         duk_int_t pc_v34_lhs;         /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
70209         duk_regconst_t temp_reset;    /* knock back "next temp" to this whenever possible */
70210         duk_regconst_t reg_temps;     /* preallocated temporaries (2) for variants 3 and 4 */
70211
70212         DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
70213
70214         /* Two temporaries are preallocated here for variants 3 and 4 which need
70215          * registers which are never clobbered by expressions in the loop
70216          * (concretely: for the enumerator object and the next enumerated value).
70217          * Variants 1 and 2 "release" these temps.
70218          */
70219
70220         reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2);
70221
70222         temp_reset = DUK__GETTEMP(comp_ctx);
70223
70224         /*
70225          *  For/for-in main variants are:
70226          *
70227          *    1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement
70228          *    2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement
70229          *    3. for (LeftHandSideExpression in Expression) Statement
70230          *    4. for (var VariableDeclarationNoIn in Expression) Statement
70231          *
70232          *  Parsing these without arbitrary lookahead or backtracking is relatively
70233          *  tricky but we manage to do so for now.
70234          *
70235          *  See doc/compiler.rst for a detailed discussion of control flow
70236          *  issues, evaluation order issues, etc.
70237          */
70238
70239         duk__advance(comp_ctx);  /* eat 'for' */
70240         duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
70241
70242         DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx)));
70243
70244         /* a label site has been emitted by duk__parse_stmt() automatically
70245          * (it will also emit the ENDLABEL).
70246          */
70247
70248         if (comp_ctx->curr_token.t == DUK_TOK_VAR) {
70249                 /*
70250                  *  Variant 2 or 4
70251                  */
70252
70253                 duk_regconst_t reg_varbind;  /* variable binding register if register-bound (otherwise < 0) */
70254                 duk_regconst_t rc_varname;   /* variable name reg/const, if variable not register-bound */
70255
70256                 duk__advance(comp_ctx);  /* eat 'var' */
70257                 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
70258                 DUK__SETTEMP(comp_ctx, temp_reset);
70259
70260                 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
70261                         /*
70262                          *  Variant 4
70263                          */
70264
70265                         DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement"));
70266                         pc_v34_lhs = duk__get_current_pc(comp_ctx);  /* jump is inserted here */
70267                         if (reg_varbind >= 0) {
70268                                 duk__emit_a_bc(comp_ctx,
70269                                                DUK_OP_LDREG,
70270                                                reg_varbind,
70271                                                reg_temps + 0);
70272                         } else {
70273                                 duk__emit_a_bc(comp_ctx,
70274                                                DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
70275                                                reg_temps + 0,
70276                                                rc_varname);
70277                         }
70278                         goto parse_3_or_4;
70279                 } else {
70280                         /*
70281                          *  Variant 2
70282                          */
70283
70284                         DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement"));
70285                         for (;;) {
70286                                 /* more initializers */
70287                                 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
70288                                         break;
70289                                 }
70290                                 DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer"));
70291
70292                                 duk__advance(comp_ctx);  /* eat comma */
70293                                 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
70294                         }
70295                         goto parse_1_or_2;
70296                 }
70297         } else {
70298                 /*
70299                  *  Variant 1 or 3
70300                  */
70301
70302                 pc_v34_lhs = duk__get_current_pc(comp_ctx);  /* jump is inserted here (variant 3) */
70303
70304                 /* Note that duk__exprtop() here can clobber any reg above current temp_next,
70305                  * so any loop variables (e.g. enumerator) must be "preallocated".
70306                  */
70307
70308                 /* don't coerce yet to a plain value (variant 3 needs special handling) */
70309                 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/);  /* Expression */
70310                 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
70311                         /*
70312                          *  Variant 3
70313                          */
70314
70315                         /* XXX: need to determine LHS type, and check that it is LHS compatible */
70316                         DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement"));
70317                         if (duk__expr_is_empty(comp_ctx)) {
70318                                 goto syntax_error;  /* LeftHandSideExpression does not allow empty expression */
70319                         }
70320
70321                         if (res->t == DUK_IVAL_VAR) {
70322                                 duk_regconst_t reg_varbind;
70323                                 duk_regconst_t rc_varname;
70324
70325                                 duk_dup(thr, res->x1.valstack_idx);
70326                                 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
70327                                         duk__emit_a_bc(comp_ctx,
70328                                                        DUK_OP_LDREG,
70329                                                        reg_varbind,
70330                                                        reg_temps + 0);
70331                                 } else {
70332                                         duk__emit_a_bc(comp_ctx,
70333                                                        DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
70334                                                        reg_temps + 0,
70335                                                        rc_varname);
70336                                 }
70337                         } else if (res->t == DUK_IVAL_PROP) {
70338                                 /* Don't allow a constant for the object (even for a number etc), as
70339                                  * it goes into the 'A' field of the opcode.
70340                                  */
70341                                 duk_regconst_t reg_obj;
70342                                 duk_regconst_t rc_key;
70343                                 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/);  /* don't allow const */
70344                                 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
70345                                 duk__emit_a_b_c(comp_ctx,
70346                                                 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
70347                                                 reg_obj,
70348                                                 rc_key,
70349                                                 reg_temps + 0);
70350                         } else {
70351                                 duk__ivalue_toplain_ignore(comp_ctx, res);  /* just in case */
70352                                 duk__emit_op_only(comp_ctx,
70353                                                   DUK_OP_INVLHS);
70354                         }
70355                         goto parse_3_or_4;
70356                 } else {
70357                         /*
70358                          *  Variant 1
70359                          */
70360
70361                         DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement"));
70362                         duk__ivalue_toplain_ignore(comp_ctx, res);
70363                         goto parse_1_or_2;
70364                 }
70365         }
70366
70367  parse_1_or_2:
70368         /*
70369          *  Parse variant 1 or 2.  The first part expression (which differs
70370          *  in the variants) has already been parsed and its code emitted.
70371          *
70372          *  reg_temps + 0: unused
70373          *  reg_temps + 1: unused
70374          */
70375         {
70376                 duk_regconst_t rc_cond;
70377                 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4;
70378                 duk_int_t pc_jumpto_l3, pc_jumpto_l4;
70379                 duk_bool_t expr_c_empty;
70380
70381                 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2"));
70382
70383                 /* "release" preallocated temps since we won't need them */
70384                 temp_reset = reg_temps + 0;
70385                 DUK__SETTEMP(comp_ctx, temp_reset);
70386
70387                 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
70388
70389                 pc_l1 = duk__get_current_pc(comp_ctx);
70390                 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/);  /* Expression_opt */
70391                 if (duk__expr_is_empty(comp_ctx)) {
70392                         /* no need to coerce */
70393                         pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx);  /* to body */
70394                         pc_jumpto_l4 = -1;  /* omitted */
70395                 } else {
70396                         rc_cond = duk__ivalue_toregconst(comp_ctx, res);
70397                         duk__emit_if_false_skip(comp_ctx, rc_cond);
70398                         pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx);  /* to body */
70399                         pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);  /* to exit */
70400                 }
70401                 DUK__SETTEMP(comp_ctx, temp_reset);
70402
70403                 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
70404
70405                 pc_l2 = duk__get_current_pc(comp_ctx);
70406                 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/);  /* Expression_opt */
70407                 if (duk__expr_is_empty(comp_ctx)) {
70408                         /* no need to coerce */
70409                         expr_c_empty = 1;
70410                         /* JUMP L1 omitted */
70411                 } else {
70412                         duk__ivalue_toplain_ignore(comp_ctx, res);
70413                         expr_c_empty = 0;
70414                         duk__emit_jump(comp_ctx, pc_l1);
70415                 }
70416                 DUK__SETTEMP(comp_ctx, temp_reset);
70417
70418                 comp_ctx->curr_func.allow_regexp_in_adv = 1;
70419                 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);  /* Allow RegExp as part of next stmt. */
70420
70421                 pc_l3 = duk__get_current_pc(comp_ctx);
70422                 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
70423                 if (expr_c_empty) {
70424                         duk__emit_jump(comp_ctx, pc_l1);
70425                 } else {
70426                         duk__emit_jump(comp_ctx, pc_l2);
70427                 }
70428                 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
70429
70430                 pc_l4 = duk__get_current_pc(comp_ctx);
70431
70432                 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, "
70433                                      "break: %ld->%ld, continue: %ld->%ld",
70434                                      (long) pc_jumpto_l3, (long) pc_l3, (long) pc_jumpto_l4, (long) pc_l4,
70435                                      (long) (pc_label_site + 1), (long) pc_l4, (long) (pc_label_site + 2), (long) pc_l2));
70436
70437                 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
70438                 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
70439                 duk__patch_jump(comp_ctx,
70440                                 pc_label_site + 1,
70441                                 pc_l4);                         /* break jump */
70442                 duk__patch_jump(comp_ctx,
70443                                 pc_label_site + 2,
70444                                 expr_c_empty ? pc_l1 : pc_l2);  /* continue jump */
70445         }
70446         goto finished;
70447
70448  parse_3_or_4:
70449         /*
70450          *  Parse variant 3 or 4.
70451          *
70452          *  For variant 3 (e.g. "for (A in C) D;") the code for A (except the
70453          *  final property/variable write) has already been emitted.  The first
70454          *  instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted
70455          *  there to satisfy control flow needs.
70456          *
70457          *  For variant 4, if the variable declaration had an initializer
70458          *  (e.g. "for (var A = B in C) D;") the code for the assignment
70459          *  (B) has already been emitted.
70460          *
70461          *  Variables set before entering here:
70462          *
70463          *    pc_v34_lhs:    insert a "JUMP L2" here (see doc/compiler.rst example).
70464          *    reg_temps + 0: iteration target value (written to LHS)
70465          *    reg_temps + 1: enumerator object
70466          */
70467         {
70468                 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
70469                 duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
70470                 duk_regconst_t reg_target;
70471
70472                 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
70473
70474                 DUK__SETTEMP(comp_ctx, temp_reset);
70475
70476                 /* First we need to insert a jump in the middle of previously
70477                  * emitted code to get the control flow right.  No jumps can
70478                  * cross the position where the jump is inserted.  See doc/compiler.rst
70479                  * for discussion on the intricacies of control flow and side effects
70480                  * for variants 3 and 4.
70481                  */
70482
70483                 duk__insert_jump_entry(comp_ctx, pc_v34_lhs);
70484                 pc_jumpto_l2 = pc_v34_lhs;  /* inserted jump */
70485                 pc_l1 = pc_v34_lhs + 1;     /* +1, right after inserted jump */
70486
70487                 /* The code for writing reg_temps + 0 to the left hand side has already
70488                  * been emitted.
70489                  */
70490
70491                 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx);  /* -> loop body */
70492
70493                 duk__advance(comp_ctx);  /* eat 'in' */
70494
70495                 /* Parse enumeration target and initialize enumerator.  For 'null' and 'undefined',
70496                  * INITENUM will creates a 'null' enumerator which works like an empty enumerator
70497                  * (E5 Section 12.6.4, step 3).  Note that INITENUM requires the value to be in a
70498                  * register (constant not allowed).
70499                  */
70500
70501                 pc_l2 = duk__get_current_pc(comp_ctx);
70502                 reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);  /* Expression */
70503                 duk__emit_b_c(comp_ctx,
70504                               DUK_OP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
70505                               reg_temps + 1,
70506                               reg_target);
70507                 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
70508                 DUK__SETTEMP(comp_ctx, temp_reset);
70509
70510                 comp_ctx->curr_func.allow_regexp_in_adv = 1;
70511                 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);  /* Allow RegExp as part of next stmt. */
70512
70513                 pc_l3 = duk__get_current_pc(comp_ctx);
70514                 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
70515                 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
70516
70517                 /* NEXTENUM needs a jump slot right after the main opcode.
70518                  * We need the code emitter to reserve the slot: if there's
70519                  * target shuffling, the target shuffle opcodes must happen
70520                  * after the jump slot (for NEXTENUM the shuffle opcodes are
70521                  * not needed if the enum is finished).
70522                  */
70523                 pc_l4 = duk__get_current_pc(comp_ctx);
70524                 duk__emit_b_c(comp_ctx,
70525                               DUK_OP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
70526                               reg_temps + 0,
70527                               reg_temps + 1);
70528                 pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc;  /* NEXTENUM jump slot: executed when enum finished */
70529                 duk__emit_jump(comp_ctx, pc_l1);  /* jump to next loop, using reg_v34_iter as iterated value */
70530
70531                 pc_l5 = duk__get_current_pc(comp_ctx);
70532
70533                 /* XXX: since the enumerator may be a memory expensive object,
70534                  * perhaps clear it explicitly here?  If so, break jump must
70535                  * go through this clearing operation.
70536                  */
70537
70538                 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, "
70539                                      "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, "
70540                                      "break: %ld->%ld, continue: %ld->%ld",
70541                                      (long) pc_jumpto_l2, (long) pc_l2, (long) pc_jumpto_l3, (long) pc_l3,
70542                                      (long) pc_jumpto_l4, (long) pc_l4, (long) pc_jumpto_l5, (long) pc_l5,
70543                                      (long) (pc_label_site + 1), (long) pc_l5, (long) (pc_label_site + 2), (long) pc_l4));
70544
70545                 duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2);
70546                 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
70547                 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
70548                 duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5);
70549                 duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5);  /* break jump */
70550                 duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4);  /* continue jump */
70551         }
70552         goto finished;
70553
70554  finished:
70555         DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement"));
70556         return;
70557
70558  syntax_error:
70559         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR);
70560         DUK_WO_NORETURN(return;);
70561 }
70562
70563 DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
70564         duk_hthread *thr = comp_ctx->thr;
70565         duk_regconst_t temp_at_loop;
70566         duk_regconst_t rc_switch;    /* reg/const for switch value */
70567         duk_regconst_t rc_case;      /* reg/const for case value */
70568         duk_regconst_t reg_temp;     /* general temp register */
70569         duk_int_t pc_prevcase = -1;
70570         duk_int_t pc_prevstmt = -1;
70571         duk_int_t pc_default = -1;   /* -1 == not set, -2 == pending (next statement list) */
70572
70573         /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
70574
70575         /*
70576          *  Switch is pretty complicated because of several conflicting concerns:
70577          *
70578          *    - Want to generate code without an intermediate representation,
70579          *      i.e., in one go
70580          *
70581          *    - Case selectors are expressions, not values, and may thus e.g. throw
70582          *      exceptions (which causes evaluation order concerns)
70583          *
70584          *    - Evaluation semantics of case selectors and default clause need to be
70585          *      carefully implemented to provide correct behavior even with case value
70586          *      side effects
70587          *
70588          *    - Fall through case and default clauses; avoiding dead JUMPs if case
70589          *      ends with an unconditional jump (a break or a continue)
70590          *
70591          *    - The same case value may occur multiple times, but evaluation rules
70592          *      only process the first match before switching to a "propagation" mode
70593          *      where case values are no longer evaluated
70594          *
70595          *  See E5 Section 12.11.  Also see doc/compiler.rst for compilation
70596          *  discussion.
70597          */
70598
70599         duk__advance(comp_ctx);
70600         duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
70601         rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
70602         duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);  /* RegExp mode does not matter. */
70603         duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
70604
70605         DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch));
70606
70607         temp_at_loop = DUK__GETTEMP(comp_ctx);
70608
70609         for (;;) {
70610                 duk_int_t num_stmts;
70611                 duk_small_uint_t tok;
70612
70613                 /* sufficient for keeping temp reg numbers in check */
70614                 DUK__SETTEMP(comp_ctx, temp_at_loop);
70615
70616                 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
70617                         break;
70618                 }
70619
70620                 /*
70621                  *  Parse a case or default clause.
70622                  */
70623
70624                 if (comp_ctx->curr_token.t == DUK_TOK_CASE) {
70625                         /*
70626                          *  Case clause.
70627                          *
70628                          *  Note: cannot use reg_case as a temp register (for SEQ target)
70629                          *  because it may be a constant.
70630                          */
70631
70632                         duk__patch_jump_here(comp_ctx, pc_prevcase);  /* chain jumps for case
70633                                                                        * evaluation and checking
70634                                                                        */
70635
70636                         duk__advance(comp_ctx);
70637                         rc_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
70638                         duk__advance_expect(comp_ctx, DUK_TOK_COLON);
70639
70640                         reg_temp = DUK__ALLOCTEMP(comp_ctx);
70641                         duk__emit_a_b_c(comp_ctx,
70642                                         DUK_OP_SEQ | DUK__EMIT_FLAG_BC_REGCONST,
70643                                         reg_temp,
70644                                         rc_switch,
70645                                         rc_case);
70646                         duk__emit_if_true_skip(comp_ctx, reg_temp);
70647
70648                         /* jump to next case clause */
70649                         pc_prevcase = duk__emit_jump_empty(comp_ctx);  /* no match, next case */
70650
70651                         /* statements go here (if any) on next loop */
70652                 } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) {
70653                         /*
70654                          *  Default clause.
70655                          */
70656
70657                         if (pc_default >= 0) {
70658                                 goto syntax_error;
70659                         }
70660                         duk__advance(comp_ctx);
70661                         duk__advance_expect(comp_ctx, DUK_TOK_COLON);
70662
70663                         /* Fix for https://github.com/svaarala/duktape/issues/155:
70664                          * If 'default' is first clause (detected by pc_prevcase < 0)
70665                          * we need to ensure we stay in the matching chain.
70666                          */
70667                         if (pc_prevcase < 0) {
70668                                 DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump"));
70669                                 pc_prevcase = duk__emit_jump_empty(comp_ctx);
70670                         }
70671
70672                         /* default clause matches next statement list (if any) */
70673                         pc_default = -2;
70674                 } else {
70675                         /* Code is not accepted before the first case/default clause */
70676                         goto syntax_error;
70677                 }
70678
70679                 /*
70680                  *  Parse code after the clause.  Possible terminators are
70681                  *  'case', 'default', and '}'.
70682                  *
70683                  *  Note that there may be no code at all, not even an empty statement,
70684                  *  between case clauses.  This must be handled just like an empty statement
70685                  *  (omitting seemingly pointless JUMPs), to avoid situations like
70686                  *  test-bug-case-fallthrough.js.
70687                  */
70688
70689                 num_stmts = 0;
70690                 if (pc_default == -2) {
70691                         pc_default = duk__get_current_pc(comp_ctx);
70692                 }
70693
70694                 /* Note: this is correct even for default clause statements:
70695                  * they participate in 'fall-through' behavior even if the
70696                  * default clause is in the middle.
70697                  */
70698                 duk__patch_jump_here(comp_ctx, pc_prevstmt);  /* chain jumps for 'fall-through'
70699                                                                * after a case matches.
70700                                                                */
70701
70702                 for (;;) {
70703                         tok = comp_ctx->curr_token.t;
70704                         if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT ||
70705                             tok == DUK_TOK_RCURLY) {
70706                                 break;
70707                         }
70708                         num_stmts++;
70709                         duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
70710                 }
70711
70712                 /* fall-through jump to next code of next case (backpatched) */
70713                 pc_prevstmt = duk__emit_jump_empty(comp_ctx);
70714
70715                 /* XXX: would be nice to omit this jump when the jump is not
70716                  * reachable, at least in the obvious cases (such as the case
70717                  * ending with a 'break'.
70718                  *
70719                  * Perhaps duk__parse_stmt() could provide some info on whether
70720                  * the statement is a "dead end"?
70721                  *
70722                  * If implemented, just set pc_prevstmt to -1 when not needed.
70723                  */
70724         }
70725
70726         DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
70727         comp_ctx->curr_func.allow_regexp_in_adv = 1;
70728         duk__advance(comp_ctx);  /* Allow RegExp as part of next stmt. */
70729
70730         /* default case control flow patchup; note that if pc_prevcase < 0
70731          * (i.e. no case clauses), control enters default case automatically.
70732          */
70733         if (pc_default >= 0) {
70734                 /* default case exists: go there if no case matches */
70735                 duk__patch_jump(comp_ctx, pc_prevcase, pc_default);
70736         } else {
70737                 /* default case does not exist, or no statements present
70738                  * after default case: finish case evaluation
70739                  */
70740                 duk__patch_jump_here(comp_ctx, pc_prevcase);
70741         }
70742
70743         /* fall-through control flow patchup; note that pc_prevstmt may be
70744          * < 0 (i.e. no case clauses), in which case this is a no-op.
70745          */
70746         duk__patch_jump_here(comp_ctx, pc_prevstmt);
70747
70748         /* continue jump not patched, an INVALID opcode remains there */
70749         duk__patch_jump_here(comp_ctx, pc_label_site + 1);  /* break jump */
70750
70751         /* Note: 'fast' breaks will jump to pc_label_site + 1, which will
70752          * then jump here.  The double jump will be eliminated by a
70753          * peephole pass, resulting in an optimal jump here.  The label
70754          * site jumps will remain in bytecode and will waste code size.
70755          */
70756
70757         return;
70758
70759  syntax_error:
70760         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH);
70761         DUK_WO_NORETURN(return;);
70762 }
70763
70764 DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
70765         duk_regconst_t temp_reset;
70766         duk_regconst_t rc_cond;
70767         duk_int_t pc_jump_false;
70768
70769         DUK_DDD(DUK_DDDPRINT("begin parsing if statement"));
70770
70771         temp_reset = DUK__GETTEMP(comp_ctx);
70772
70773         duk__advance(comp_ctx);  /* eat 'if' */
70774         duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
70775
70776         rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
70777         duk__emit_if_true_skip(comp_ctx, rc_cond);
70778         pc_jump_false = duk__emit_jump_empty(comp_ctx);  /* jump to end or else part */
70779         DUK__SETTEMP(comp_ctx, temp_reset);
70780
70781         comp_ctx->curr_func.allow_regexp_in_adv = 1;
70782         duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);  /* Allow RegExp as part of next stmt. */
70783
70784         duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
70785
70786         /* The 'else' ambiguity is resolved by 'else' binding to the innermost
70787          * construct, so greedy matching is correct here.
70788          */
70789
70790         if (comp_ctx->curr_token.t == DUK_TOK_ELSE) {
70791                 duk_int_t pc_jump_end;
70792
70793                 DUK_DDD(DUK_DDDPRINT("if has else part"));
70794
70795                 duk__advance(comp_ctx);
70796
70797                 pc_jump_end = duk__emit_jump_empty(comp_ctx);  /* jump from true part to end */
70798                 duk__patch_jump_here(comp_ctx, pc_jump_false);
70799
70800                 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
70801
70802                 duk__patch_jump_here(comp_ctx, pc_jump_end);
70803         } else {
70804                 DUK_DDD(DUK_DDDPRINT("if does not have else part"));
70805
70806                 duk__patch_jump_here(comp_ctx, pc_jump_false);
70807         }
70808
70809         DUK_DDD(DUK_DDDPRINT("end parsing if statement"));
70810 }
70811
70812 DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
70813         duk_regconst_t rc_cond;
70814         duk_int_t pc_start;
70815
70816         DUK_DDD(DUK_DDDPRINT("begin parsing do statement"));
70817
70818         duk__advance(comp_ctx);  /* Eat 'do'; allow RegExp as part of next stmt. */
70819
70820         pc_start = duk__get_current_pc(comp_ctx);
70821         duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
70822         duk__patch_jump_here(comp_ctx, pc_label_site + 2);  /* continue jump */
70823
70824         duk__advance_expect(comp_ctx, DUK_TOK_WHILE);
70825         duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
70826
70827         rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
70828         duk__emit_if_false_skip(comp_ctx, rc_cond);
70829         duk__emit_jump(comp_ctx, pc_start);
70830         /* no need to reset temps, as we're finished emitting code */
70831
70832         comp_ctx->curr_func.allow_regexp_in_adv = 1;  /* Allow RegExp as part of next stmt. */
70833         duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
70834
70835         duk__patch_jump_here(comp_ctx, pc_label_site + 1);  /* break jump */
70836
70837         DUK_DDD(DUK_DDDPRINT("end parsing do statement"));
70838 }
70839
70840 DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
70841         duk_regconst_t temp_reset;
70842         duk_regconst_t rc_cond;
70843         duk_int_t pc_start;
70844         duk_int_t pc_jump_false;
70845
70846         DUK_DDD(DUK_DDDPRINT("begin parsing while statement"));
70847
70848         temp_reset = DUK__GETTEMP(comp_ctx);
70849
70850         duk__advance(comp_ctx);  /* eat 'while' */
70851
70852         duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
70853
70854         pc_start = duk__get_current_pc(comp_ctx);
70855         duk__patch_jump_here(comp_ctx, pc_label_site + 2);  /* continue jump */
70856
70857         rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
70858         duk__emit_if_true_skip(comp_ctx, rc_cond);
70859         pc_jump_false = duk__emit_jump_empty(comp_ctx);
70860         DUK__SETTEMP(comp_ctx, temp_reset);
70861
70862         comp_ctx->curr_func.allow_regexp_in_adv = 1;
70863         duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);  /* Allow RegExp as part of next stmt. */
70864
70865         duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
70866         duk__emit_jump(comp_ctx, pc_start);
70867
70868         duk__patch_jump_here(comp_ctx, pc_jump_false);
70869         duk__patch_jump_here(comp_ctx, pc_label_site + 1);  /* break jump */
70870
70871         DUK_DDD(DUK_DDDPRINT("end parsing while statement"));
70872 }
70873
70874 DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
70875         duk_hthread *thr = comp_ctx->thr;
70876         duk_bool_t is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK);
70877         duk_int_t label_id;
70878         duk_int_t label_catch_depth;
70879         duk_int_t label_pc;  /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */
70880         duk_bool_t label_is_closest;
70881
70882         DUK_UNREF(res);
70883
70884         duk__advance(comp_ctx);  /* eat 'break' or 'continue' */
70885
70886         if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON ||  /* explicit semi follows */
70887             comp_ctx->curr_token.lineterm ||                /* automatic semi will be inserted */
70888             comp_ctx->curr_token.allow_auto_semi) {         /* automatic semi will be inserted */
70889                 /* break/continue without label */
70890
70891                 duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
70892         } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) {
70893                 /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */
70894                 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
70895                 duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
70896                 duk__advance(comp_ctx);
70897         } else {
70898                 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL);
70899                 DUK_WO_NORETURN(return;);
70900         }
70901
70902         /* Use a fast break/continue when possible.  A fast break/continue is
70903          * just a jump to the LABEL break/continue jump slot, which then jumps
70904          * to an appropriate place (for break, going through ENDLABEL correctly).
70905          * The peephole optimizer will optimize the jump to a direct one.
70906          */
70907
70908         if (label_catch_depth == comp_ctx->curr_func.catch_depth &&
70909             label_is_closest) {
70910                 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
70911                                      "label_catch_depth=%ld, catch_depth=%ld "
70912                                      "-> use fast variant (direct jump)",
70913                                      (long) is_break, (long) label_id, (long) label_is_closest,
70914                                      (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
70915
70916                 duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2));
70917         } else {
70918                 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
70919                                      "label_catch_depth=%ld, catch_depth=%ld "
70920                                      "-> use slow variant (longjmp)",
70921                                      (long) is_break, (long) label_id, (long) label_is_closest,
70922                                      (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
70923
70924                 duk__emit_bc(comp_ctx,
70925                              is_break ? DUK_OP_BREAK : DUK_OP_CONTINUE,
70926                              (duk_regconst_t) label_id);
70927         }
70928 }
70929
70930 DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
70931         duk_hthread *thr = comp_ctx->thr;
70932         duk_regconst_t rc_val;
70933
70934         duk__advance(comp_ctx);  /* eat 'return' */
70935
70936         /* A 'return' statement is only allowed inside an actual function body,
70937          * not as part of eval or global code.
70938          */
70939         if (!comp_ctx->curr_func.is_function) {
70940                 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN);
70941                 DUK_WO_NORETURN(return;);
70942         }
70943
70944         if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON ||  /* explicit semi follows */
70945             comp_ctx->curr_token.lineterm ||                /* automatic semi will be inserted */
70946             comp_ctx->curr_token.allow_auto_semi) {         /* automatic semi will be inserted */
70947                 DUK_DDD(DUK_DDDPRINT("empty return value -> undefined"));
70948                 duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
70949         } else {
70950                 duk_int_t pc_before_expr;
70951                 duk_int_t pc_after_expr;
70952
70953                 DUK_DDD(DUK_DDDPRINT("return with a value"));
70954
70955                 DUK_UNREF(pc_before_expr);
70956                 DUK_UNREF(pc_after_expr);
70957
70958                 pc_before_expr = duk__get_current_pc(comp_ctx);
70959                 rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
70960                 pc_after_expr = duk__get_current_pc(comp_ctx);
70961
70962                 /* Tail call check: if last opcode emitted was CALL, and
70963                  * the context allows it, add a tailcall flag to the CALL.
70964                  * This doesn't guarantee that a tail call will be allowed at
70965                  * runtime, so the RETURN must still be emitted.  (Duktape
70966                  * 0.10.0 avoided this and simulated a RETURN if a tail call
70967                  * couldn't be used at runtime; but this didn't work
70968                  * correctly with a thread yield/resume, see
70969                  * test-bug-tailcall-thread-yield-resume.js for discussion.)
70970                  *
70971                  * In addition to the last opcode being CALL, we also need to
70972                  * be sure that 'rc_val' is the result register of the CALL.
70973                  * For instance, for the expression 'return 0, (function ()
70974                  * { return 1; }), 2' the last opcode emitted is CALL (no
70975                  * bytecode is emitted for '2') but 'rc_val' indicates
70976                  * constant '2'.  Similarly if '2' is replaced by a register
70977                  * bound variable, no opcodes are emitted but tail call would
70978                  * be incorrect.
70979                  *
70980                  * This is tricky and easy to get wrong.  It would be best to
70981                  * track enough expression metadata to check that 'rc_val' came
70982                  * from that last CALL instruction.  We don't have that metadata
70983                  * now, so we check that 'rc_val' is a temporary register result
70984                  * (not a constant or a register bound variable).  There should
70985                  * be no way currently for 'rc_val' to be a temporary for an
70986                  * expression following the CALL instruction without emitting
70987                  * some opcodes following the CALL.  This proxy check is used
70988                  * below.
70989                  *
70990                  * See: test-bug-comma-expr-gh131.js.
70991                  *
70992                  * The non-standard 'caller' property disables tail calls
70993                  * because they pose some special cases which haven't been
70994                  * fixed yet.
70995                  */
70996
70997 #if defined(DUK_USE_TAILCALL)
70998                 if (comp_ctx->curr_func.catch_depth == 0 &&   /* no catchers */
70999                     pc_after_expr > pc_before_expr) {         /* at least one opcode emitted */
71000                         duk_compiler_instr *instr;
71001                         duk_instr_t ins;
71002                         duk_small_uint_t op;
71003
71004                         instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
71005                         DUK_ASSERT(instr != NULL);
71006
71007                         ins = instr->ins;
71008                         op = (duk_small_uint_t) DUK_DEC_OP(ins);
71009                         if ((op & ~0x0fU) == DUK_OP_CALL0 &&
71010                             DUK__ISREG_TEMP(comp_ctx, rc_val) /* see above */) {
71011                                 DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
71012                                                      "catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
71013                                                      "and last instruction is a CALL "
71014                                                      "-> change to TAILCALL"));
71015                                 ins |= DUK_ENC_OP(DUK_BC_CALL_FLAG_TAILCALL);
71016                                 instr->ins = ins;
71017                         }
71018                 }
71019 #endif  /* DUK_USE_TAILCALL */
71020
71021                 if (DUK__ISREG(rc_val)) {
71022                         duk__emit_bc(comp_ctx, DUK_OP_RETREG, rc_val);
71023                 } else {
71024                         rc_val = DUK__REMOVECONST(rc_val);
71025                         if (duk__const_needs_refcount(comp_ctx, rc_val)) {
71026                                 duk__emit_bc(comp_ctx, DUK_OP_RETCONST, rc_val);
71027                         } else {
71028                                 duk__emit_bc(comp_ctx, DUK_OP_RETCONSTN, rc_val);
71029                         }
71030                 }
71031         }
71032 }
71033
71034 DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
71035         duk_regconst_t reg_val;
71036
71037         duk__advance(comp_ctx);  /* eat 'throw' */
71038
71039         /* Unlike break/continue, throw statement does not allow an empty value. */
71040
71041         if (comp_ctx->curr_token.lineterm) {
71042                 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW);
71043                 DUK_WO_NORETURN(return;);
71044         }
71045
71046         reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
71047         duk__emit_bc(comp_ctx,
71048                      DUK_OP_THROW,
71049                      reg_val);
71050 }
71051
71052 DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
71053         duk_hthread *thr = comp_ctx->thr;
71054         duk_regconst_t reg_catch;      /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
71055         duk_regconst_t rc_varname = 0;
71056         duk_small_uint_t trycatch_flags = 0;
71057         duk_int_t pc_ldconst = -1;
71058         duk_int_t pc_trycatch = -1;
71059         duk_int_t pc_catch = -1;
71060         duk_int_t pc_finally = -1;
71061
71062         DUK_UNREF(res);
71063
71064         /*
71065          *  See the following documentation for discussion:
71066          *
71067          *    doc/execution.rst: control flow details
71068          *
71069          *  Try, catch, and finally "parts" are Blocks, not Statements, so
71070          *  they must always be delimited by curly braces.  This is unlike e.g.
71071          *  the if statement, which accepts any Statement.  This eliminates any
71072          *  questions of matching parts of nested try statements.  The Block
71073          *  parsing is implemented inline here (instead of calling out).
71074          *
71075          *  Finally part has a 'let scoped' variable, which requires a few kinks
71076          *  here.
71077          */
71078
71079         comp_ctx->curr_func.catch_depth++;
71080
71081         duk__advance(comp_ctx);  /* eat 'try' */
71082
71083         reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
71084
71085         /* The target for this LDCONST may need output shuffling, but we assume
71086          * that 'pc_ldconst' will be the LDCONST that we can patch later.  This
71087          * should be the case because there's no input shuffling.  (If there's
71088          * no catch clause, this LDCONST will be replaced with a NOP.)
71089          */
71090         pc_ldconst = duk__get_current_pc(comp_ctx);
71091         duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/);
71092
71093         pc_trycatch = duk__get_current_pc(comp_ctx);
71094         duk__emit_invalid(comp_ctx);  /* TRYCATCH, cannot emit now (not enough info) */
71095         duk__emit_invalid(comp_ctx);  /* jump for 'catch' case */
71096         duk__emit_invalid(comp_ctx);  /* jump for 'finally' case or end (if no finally) */
71097
71098         /* try part */
71099         duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
71100         duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/);
71101         /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
71102         duk__emit_op_only(comp_ctx, DUK_OP_ENDTRY);
71103
71104         if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
71105                 /*
71106                  *  The catch variable must be updated to reflect the new allocated
71107                  *  register for the duration of the catch clause.  We need to store
71108                  *  and restore the original value for the varmap entry (if any).
71109                  */
71110
71111                 /*
71112                  *  Note: currently register bindings must be fixed for the entire
71113                  *  function.  So, even though the catch variable is in a register
71114                  *  we know, we must use an explicit environment record and slow path
71115                  *  accesses to read/write the catch binding to make closures created
71116                  *  within the catch clause work correctly.  This restriction should
71117                  *  be fixable (at least in common cases) later.
71118                  *
71119                  *  See: test-bug-catch-binding-2.js.
71120                  *
71121                  *  XXX: improve to get fast path access to most catch clauses.
71122                  */
71123
71124                 duk_hstring *h_var;
71125                 duk_int_t varmap_value;  /* for storing/restoring the varmap binding for catch variable */
71126
71127                 DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(thr)));
71128
71129                 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
71130
71131                 pc_catch = duk__get_current_pc(comp_ctx);
71132
71133                 duk__advance(comp_ctx);
71134                 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
71135
71136                 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
71137                         /* Identifier, i.e. don't allow reserved words */
71138                         goto syntax_error;
71139                 }
71140                 h_var = comp_ctx->curr_token.str1;
71141                 DUK_ASSERT(h_var != NULL);
71142
71143                 duk_push_hstring(thr, h_var);  /* keep in on valstack, use borrowed ref below */
71144
71145                 if (comp_ctx->curr_func.is_strict &&
71146                     ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
71147                      (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) {
71148                         DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError"));
71149                         goto syntax_error;
71150                 }
71151
71152                 duk_dup_top(thr);
71153                 rc_varname = duk__getconst(comp_ctx);
71154                 DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
71155                                      (unsigned long) rc_varname, (long) rc_varname));
71156
71157                 duk__advance(comp_ctx);
71158                 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
71159
71160                 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
71161
71162                 DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
71163                                      (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
71164
71165                 duk_dup_top(thr);
71166                 duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
71167                 if (duk_is_undefined(thr, -1)) {
71168                         varmap_value = -2;
71169                 } else if (duk_is_null(thr, -1)) {
71170                         varmap_value = -1;
71171                 } else {
71172                         DUK_ASSERT(duk_is_number(thr, -1));
71173                         varmap_value = duk_get_int(thr, -1);
71174                         DUK_ASSERT(varmap_value >= 0);
71175                 }
71176                 duk_pop(thr);
71177
71178 #if 0
71179                 /* It'd be nice to do something like this - but it doesn't
71180                  * work for closures created inside the catch clause.
71181                  */
71182                 duk_dup_top(thr);
71183                 duk_push_int(thr, (duk_int_t) (reg_catch + 0));
71184                 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
71185 #endif
71186                 duk_dup_top(thr);
71187                 duk_push_null(thr);
71188                 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
71189
71190                 duk__emit_a_bc(comp_ctx,
71191                                DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
71192                                reg_catch + 0 /*value*/,
71193                                rc_varname /*varname*/);
71194
71195                 DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
71196                                      (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
71197
71198                 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/);
71199                 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
71200
71201                 if (varmap_value == -2) {
71202                         /* not present */
71203                         duk_del_prop(thr, comp_ctx->curr_func.varmap_idx);
71204                 } else {
71205                         if (varmap_value == -1) {
71206                                 duk_push_null(thr);
71207                         } else {
71208                                 DUK_ASSERT(varmap_value >= 0);
71209                                 duk_push_int(thr, varmap_value);
71210                         }
71211                         duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);
71212                 }
71213                 /* varname is popped by above code */
71214
71215                 DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
71216                                      (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx)));
71217
71218                 duk__emit_op_only(comp_ctx,
71219                                   DUK_OP_ENDCATCH);
71220
71221                 /*
71222                  *  XXX: for now, indicate that an expensive catch binding
71223                  *  declarative environment is always needed.  If we don't
71224                  *  need it, we don't need the const_varname either.
71225                  */
71226
71227                 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
71228
71229                 DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(thr)));
71230         }
71231
71232         if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
71233                 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY;
71234
71235                 pc_finally = duk__get_current_pc(comp_ctx);
71236
71237                 duk__advance(comp_ctx);
71238
71239                 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
71240                 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/);
71241                 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
71242                 duk__emit_abc(comp_ctx,
71243                               DUK_OP_ENDFIN,
71244                               reg_catch);  /* rethrow */
71245         }
71246
71247         if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
71248             !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) {
71249                 /* must have catch and/or finally */
71250                 goto syntax_error;
71251         }
71252
71253         /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch()
71254          * will replace the LDCONST with a NOP.  For any actual constant (including
71255          * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname.
71256          */
71257
71258         duk__patch_trycatch(comp_ctx,
71259                             pc_ldconst,
71260                             pc_trycatch,
71261                             reg_catch,
71262                             rc_varname,
71263                             trycatch_flags);
71264
71265         if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
71266                 DUK_ASSERT(pc_catch >= 0);
71267                 duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch);
71268         }
71269
71270         if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
71271                 DUK_ASSERT(pc_finally >= 0);
71272                 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally);
71273         } else {
71274                 /* without finally, the second jump slot is used to jump to end of stmt */
71275                 duk__patch_jump_here(comp_ctx, pc_trycatch + 2);
71276         }
71277
71278         comp_ctx->curr_func.catch_depth--;
71279         return;
71280
71281  syntax_error:
71282         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY);
71283         DUK_WO_NORETURN(return;);
71284 }
71285
71286 DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
71287         duk_int_t pc_trycatch;
71288         duk_int_t pc_finished;
71289         duk_regconst_t reg_catch;
71290         duk_small_uint_t trycatch_flags;
71291
71292         if (comp_ctx->curr_func.is_strict) {
71293                 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE);
71294                 DUK_WO_NORETURN(return;);
71295         }
71296
71297         comp_ctx->curr_func.catch_depth++;
71298
71299         duk__advance(comp_ctx);  /* eat 'with' */
71300
71301         reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
71302
71303         duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
71304         duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch);
71305         comp_ctx->curr_func.allow_regexp_in_adv = 1;
71306         duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);  /* Allow RegExp as part of next stmt. */
71307
71308         pc_trycatch = duk__get_current_pc(comp_ctx);
71309         trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING;
71310         duk__emit_a_bc(comp_ctx,
71311                         DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A,
71312                         (duk_regconst_t) trycatch_flags /*a*/,
71313                         reg_catch /*bc*/);
71314         duk__emit_invalid(comp_ctx);  /* catch jump */
71315         duk__emit_invalid(comp_ctx);  /* finished jump */
71316
71317         duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
71318         duk__emit_op_only(comp_ctx, DUK_OP_ENDTRY);
71319
71320         pc_finished = duk__get_current_pc(comp_ctx);
71321
71322         duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished);
71323
71324         comp_ctx->curr_func.catch_depth--;
71325 }
71326
71327 DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id) {
71328         /* if a site already exists, nop: max one label site per statement */
71329         if (label_id >= 0) {
71330                 return label_id;
71331         }
71332
71333         label_id = comp_ctx->curr_func.label_next++;
71334         DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id));
71335
71336         duk__emit_bc(comp_ctx,
71337                      DUK_OP_LABEL,
71338                      (duk_regconst_t) label_id);
71339         duk__emit_invalid(comp_ctx);
71340         duk__emit_invalid(comp_ctx);
71341
71342         return label_id;
71343 }
71344
71345 /* Parse a single statement.
71346  *
71347  * Creates a label site (with an empty label) automatically for iteration
71348  * statements.  Also "peels off" any label statements for explicit labels.
71349  */
71350 DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) {
71351         duk_hthread *thr = comp_ctx->thr;
71352         duk_bool_t dir_prol_at_entry;    /* directive prologue status at entry */
71353         duk_regconst_t temp_at_entry;
71354         duk_size_t labels_len_at_entry;
71355         duk_int_t pc_at_entry;           /* assumed to also be PC of "LABEL" */
71356         duk_int_t stmt_id;
71357         duk_small_uint_t stmt_flags = 0;
71358         duk_int_t label_id = -1;
71359         duk_small_uint_t tok;
71360         duk_bool_t test_func_decl;
71361
71362         DUK__RECURSION_INCREASE(comp_ctx, thr);
71363
71364         temp_at_entry = DUK__GETTEMP(comp_ctx);
71365         pc_at_entry = duk__get_current_pc(comp_ctx);
71366         labels_len_at_entry = duk_get_length(thr, comp_ctx->curr_func.labelnames_idx);
71367         stmt_id = comp_ctx->curr_func.stmt_next++;
71368         dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
71369
71370         DUK_UNREF(stmt_id);
71371
71372         DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, "
71373                              "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld",
71374                              (long) stmt_id, (long) temp_at_entry, (long) labels_len_at_entry,
71375                              (long) comp_ctx->curr_func.is_strict, (long) comp_ctx->curr_func.in_directive_prologue,
71376                              (long) comp_ctx->curr_func.catch_depth));
71377
71378         /* The directive prologue flag is cleared by default so that it is
71379          * unset for any recursive statement parsing.  It is only "revived"
71380          * if a directive is detected.  (We could also make directives only
71381          * allowed if 'allow_source_elem' was true.)
71382          */
71383         comp_ctx->curr_func.in_directive_prologue = 0;
71384
71385  retry_parse:
71386
71387         DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld",
71388                              (long) stmt_id, (long) label_id, (long) allow_source_elem,
71389                              (long) comp_ctx->curr_func.catch_depth));
71390
71391         /*
71392          *  Detect iteration statements; if encountered, establish an
71393          *  empty label.
71394          */
71395
71396         tok = comp_ctx->curr_token.t;
71397         if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE ||
71398             tok == DUK_TOK_SWITCH) {
71399                 DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label"));
71400
71401                 label_id = duk__stmt_label_site(comp_ctx, label_id);
71402                 duk__add_label(comp_ctx,
71403                                DUK_HTHREAD_STRING_EMPTY_STRING(thr),
71404                                pc_at_entry /*pc_label*/,
71405                                label_id);
71406         }
71407
71408         /*
71409          *  Main switch for statement / source element type.
71410          */
71411
71412         switch (comp_ctx->curr_token.t) {
71413         case DUK_TOK_FUNCTION: {
71414                 /*
71415                  *  Function declaration, function expression, or (non-standard)
71416                  *  function statement.
71417                  *
71418                  *  The E5 specification only allows function declarations at
71419                  *  the top level (in "source elements").  An ExpressionStatement
71420                  *  is explicitly not allowed to begin with a "function" keyword
71421                  *  (E5 Section 12.4).  Hence any non-error semantics for such
71422                  *  non-top-level statements are non-standard.  Duktape semantics
71423                  *  for function statements are modelled after V8, see
71424                  *  test-dev-func-decl-outside-top.js.
71425                  */
71426                 test_func_decl = allow_source_elem;
71427 #if defined(DUK_USE_NONSTD_FUNC_STMT)
71428                 /* Lenient: allow function declarations outside top level in
71429                  * non-strict mode but reject them in strict mode.
71430                  */
71431                 test_func_decl = test_func_decl || !comp_ctx->curr_func.is_strict;
71432 #endif  /* DUK_USE_NONSTD_FUNC_STMT */
71433                 /* Strict: never allow function declarations outside top level. */
71434                 if (test_func_decl) {
71435                         /* FunctionDeclaration: not strictly a statement but handled as such.
71436                          *
71437                          * O(depth^2) parse count for inner functions is handled by recording a
71438                          * lexer offset on the first compilation pass, so that the function can
71439                          * be efficiently skipped on the second pass.  This is encapsulated into
71440                          * duk__parse_func_like_fnum().
71441                          */
71442
71443                         duk_int_t fnum;
71444 #if defined(DUK_USE_ASSERTIONS)
71445                         duk_idx_t top_before;
71446 #endif
71447
71448                         DUK_DDD(DUK_DDDPRINT("function declaration statement"));
71449
71450 #if defined(DUK_USE_ASSERTIONS)
71451                         top_before = duk_get_top(thr);
71452 #endif
71453
71454                         duk__advance(comp_ctx);  /* eat 'function' */
71455                         fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_DECL | DUK__FUNC_FLAG_PUSHNAME_PASS1);
71456
71457                         /* The value stack convention here is a bit odd: the function
71458                          * name is only pushed on pass 1 (in_scanning), and is needed
71459                          * to process function declarations.
71460                          */
71461                         if (comp_ctx->curr_func.in_scanning) {
71462                                 duk_uarridx_t n;
71463
71464 #if defined(DUK_USE_ASSERTIONS)
71465                                 DUK_ASSERT(duk_get_top(thr) == top_before + 1);
71466 #endif
71467                                 DUK_DDD(DUK_DDDPRINT("register function declaration %!T in pass 1, fnum %ld",
71468                                                      duk_get_tval(thr, -1), (long) fnum));
71469                                 n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
71470                                 /* funcname is at index -1 */
71471                                 duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n);
71472                                 duk_push_int(thr, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
71473                                 duk_put_prop_index(thr, comp_ctx->curr_func.decls_idx, n + 1);
71474                         } else {
71475 #if defined(DUK_USE_ASSERTIONS)
71476                                 DUK_ASSERT(duk_get_top(thr) == top_before);
71477 #endif
71478                         }
71479
71480                         /* no statement value (unlike function expression) */
71481                         stmt_flags = 0;
71482                         break;
71483                 } else {
71484                         DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED);
71485                         DUK_WO_NORETURN(return;);
71486                 }
71487                 break;
71488         }
71489         case DUK_TOK_LCURLY: {
71490                 DUK_DDD(DUK_DDDPRINT("block statement"));
71491                 duk__advance(comp_ctx);
71492                 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/, 1 /*regexp_after*/);
71493                 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
71494                 if (label_id >= 0) {
71495                         duk__patch_jump_here(comp_ctx, pc_at_entry + 1);  /* break jump */
71496                 }
71497                 stmt_flags = 0;
71498                 break;
71499         }
71500         case DUK_TOK_CONST: {
71501                 DUK_DDD(DUK_DDDPRINT("constant declaration statement"));
71502                 duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/);
71503                 stmt_flags = DUK__HAS_TERM;
71504                 break;
71505         }
71506         case DUK_TOK_VAR: {
71507                 DUK_DDD(DUK_DDDPRINT("variable declaration statement"));
71508                 duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/);
71509                 stmt_flags = DUK__HAS_TERM;
71510                 break;
71511         }
71512         case DUK_TOK_SEMICOLON: {
71513                 /* empty statement with an explicit semicolon */
71514                 DUK_DDD(DUK_DDDPRINT("empty statement"));
71515                 stmt_flags = DUK__HAS_TERM;
71516                 break;
71517         }
71518         case DUK_TOK_IF: {
71519                 DUK_DDD(DUK_DDDPRINT("if statement"));
71520                 duk__parse_if_stmt(comp_ctx, res);
71521                 if (label_id >= 0) {
71522                         duk__patch_jump_here(comp_ctx, pc_at_entry + 1);  /* break jump */
71523                 }
71524                 stmt_flags = 0;
71525                 break;
71526         }
71527         case DUK_TOK_DO: {
71528                 /*
71529                  *  Do-while statement is mostly trivial, but there is special
71530                  *  handling for automatic semicolon handling (triggered by the
71531                  *  DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at:
71532                  *
71533                  *    https://bugs.ecmascript.org/show_bug.cgi?id=8
71534                  *
71535                  *  See doc/compiler.rst for details.
71536                  */
71537                 DUK_DDD(DUK_DDDPRINT("do statement"));
71538                 DUK_ASSERT(label_id >= 0);
71539                 duk__update_label_flags(comp_ctx,
71540                                         label_id,
71541                                         DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
71542                 duk__parse_do_stmt(comp_ctx, res, pc_at_entry);
71543                 stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS;  /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */
71544                 break;
71545         }
71546         case DUK_TOK_WHILE: {
71547                 DUK_DDD(DUK_DDDPRINT("while statement"));
71548                 DUK_ASSERT(label_id >= 0);
71549                 duk__update_label_flags(comp_ctx,
71550                                         label_id,
71551                                         DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
71552                 duk__parse_while_stmt(comp_ctx, res, pc_at_entry);
71553                 stmt_flags = 0;
71554                 break;
71555         }
71556         case DUK_TOK_FOR: {
71557                 /*
71558                  *  For/for-in statement is complicated to parse because
71559                  *  determining the statement type (three-part for vs. a
71560                  *  for-in) requires potential backtracking.
71561                  *
71562                  *  See the helper for the messy stuff.
71563                  */
71564                 DUK_DDD(DUK_DDDPRINT("for/for-in statement"));
71565                 DUK_ASSERT(label_id >= 0);
71566                 duk__update_label_flags(comp_ctx,
71567                                         label_id,
71568                                         DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
71569                 duk__parse_for_stmt(comp_ctx, res, pc_at_entry);
71570                 stmt_flags = 0;
71571                 break;
71572         }
71573         case DUK_TOK_CONTINUE:
71574         case DUK_TOK_BREAK: {
71575                 DUK_DDD(DUK_DDDPRINT("break/continue statement"));
71576                 duk__parse_break_or_continue_stmt(comp_ctx, res);
71577                 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
71578                 break;
71579         }
71580         case DUK_TOK_RETURN: {
71581                 DUK_DDD(DUK_DDDPRINT("return statement"));
71582                 duk__parse_return_stmt(comp_ctx, res);
71583                 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
71584                 break;
71585         }
71586         case DUK_TOK_WITH: {
71587                 DUK_DDD(DUK_DDDPRINT("with statement"));
71588                 comp_ctx->curr_func.with_depth++;
71589                 duk__parse_with_stmt(comp_ctx, res);
71590                 if (label_id >= 0) {
71591                         duk__patch_jump_here(comp_ctx, pc_at_entry + 1);  /* break jump */
71592                 }
71593                 comp_ctx->curr_func.with_depth--;
71594                 stmt_flags = 0;
71595                 break;
71596         }
71597         case DUK_TOK_SWITCH: {
71598                 /*
71599                  *  The switch statement is pretty messy to compile.
71600                  *  See the helper for details.
71601                  */
71602                 DUK_DDD(DUK_DDDPRINT("switch statement"));
71603                 DUK_ASSERT(label_id >= 0);
71604                 duk__update_label_flags(comp_ctx,
71605                                         label_id,
71606                                         DUK_LABEL_FLAG_ALLOW_BREAK);  /* don't allow continue */
71607                 duk__parse_switch_stmt(comp_ctx, res, pc_at_entry);
71608                 stmt_flags = 0;
71609                 break;
71610         }
71611         case DUK_TOK_THROW: {
71612                 DUK_DDD(DUK_DDDPRINT("throw statement"));
71613                 duk__parse_throw_stmt(comp_ctx, res);
71614                 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
71615                 break;
71616         }
71617         case DUK_TOK_TRY: {
71618                 DUK_DDD(DUK_DDDPRINT("try statement"));
71619                 duk__parse_try_stmt(comp_ctx, res);
71620                 stmt_flags = 0;
71621                 break;
71622         }
71623         case DUK_TOK_DEBUGGER: {
71624                 duk__advance(comp_ctx);
71625 #if defined(DUK_USE_DEBUGGER_SUPPORT)
71626                 DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode"));
71627                 duk__emit_op_only(comp_ctx, DUK_OP_DEBUGGER);
71628 #else
71629                 DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
71630 #endif
71631                 stmt_flags = DUK__HAS_TERM;
71632                 break;
71633         }
71634         default: {
71635                 /*
71636                  *  Else, must be one of:
71637                  *    - ExpressionStatement, possibly a directive (String)
71638                  *    - LabelledStatement (Identifier followed by ':')
71639                  *
71640                  *  Expressions beginning with 'function' keyword are covered by a case
71641                  *  above (such expressions are not allowed in standard E5 anyway).
71642                  *  Also expressions starting with '{' are interpreted as block
71643                  *  statements.  See E5 Section 12.4.
71644                  *
71645                  *  Directive detection is tricky; see E5 Section 14.1 on directive
71646                  *  prologue.  A directive is an expression statement with a single
71647                  *  string literal and an explicit or automatic semicolon.  Escape
71648                  *  characters are significant and no parens etc are allowed:
71649                  *
71650                  *    'use strict';          // valid 'use strict' directive
71651                  *    'use\u0020strict';     // valid directive, not a 'use strict' directive
71652                  *    ('use strict');        // not a valid directive
71653                  *
71654                  *  The expression is determined to consist of a single string literal
71655                  *  based on duk__expr_nud() and duk__expr_led() call counts.  The string literal
71656                  *  of a 'use strict' directive is determined to lack any escapes based
71657                  *  num_escapes count from the lexer.  Note that other directives may be
71658                  *  allowed to contain escapes, so a directive with escapes does not
71659                  *  terminate a directive prologue.
71660                  *
71661                  *  We rely on the fact that the expression parser will not emit any
71662                  *  code for a single token expression.  However, it will generate an
71663                  *  intermediate value which we will then successfully ignore.
71664                  *
71665                  *  A similar approach is used for labels.
71666                  */
71667
71668                 duk_bool_t single_token;
71669
71670                 DUK_DDD(DUK_DDDPRINT("expression statement"));
71671                 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
71672
71673                 single_token = (comp_ctx->curr_func.nud_count == 1 &&  /* one token */
71674                                 comp_ctx->curr_func.led_count == 0);   /* no operators */
71675
71676                 if (single_token &&
71677                     comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
71678                     comp_ctx->curr_token.t == DUK_TOK_COLON) {
71679                         /*
71680                          *  Detected label
71681                          */
71682
71683                         duk_hstring *h_lab;
71684
71685                         /* expected ival */
71686                         DUK_ASSERT(res->t == DUK_IVAL_VAR);
71687                         DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
71688                         DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx)));
71689                         h_lab = comp_ctx->prev_token.str1;
71690                         DUK_ASSERT(h_lab != NULL);
71691
71692                         DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'",
71693                                              (duk_heaphdr *) h_lab));
71694
71695                         duk__advance(comp_ctx);  /* eat colon */
71696
71697                         label_id = duk__stmt_label_site(comp_ctx, label_id);
71698
71699                         duk__add_label(comp_ctx,
71700                                        h_lab,
71701                                        pc_at_entry /*pc_label*/,
71702                                        label_id);
71703
71704                         /* a statement following a label cannot be a source element
71705                          * (a function declaration).
71706                          */
71707                         allow_source_elem = 0;
71708
71709                         DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing"));
71710                         goto retry_parse;
71711                 }
71712
71713                 stmt_flags = 0;
71714
71715                 if (dir_prol_at_entry &&                           /* still in prologue */
71716                     single_token &&                                /* single string token */
71717                     comp_ctx->prev_token.t == DUK_TOK_STRING) {
71718                         /*
71719                          *  Detected a directive
71720                          */
71721                         duk_hstring *h_dir;
71722
71723                         /* expected ival */
71724                         DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
71725                         DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
71726                         DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(thr, res->x1.valstack_idx)));
71727                         h_dir = comp_ctx->prev_token.str1;
71728                         DUK_ASSERT(h_dir != NULL);
71729
71730                         DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir));
71731
71732                         stmt_flags |= DUK__STILL_PROLOGUE;
71733
71734                         /* Note: escaped characters differentiate directives */
71735
71736                         if (comp_ctx->prev_token.num_escapes > 0) {
71737                                 DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive "
71738                                                      "but we ignore such directives"));
71739                         } else {
71740                                 /*
71741                                  * The length comparisons are present to handle
71742                                  * strings like "use strict\u0000foo" as required.
71743                                  */
71744
71745                                 if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 &&
71746                                     DUK_STRCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict") == 0) {
71747 #if defined(DUK_USE_STRICT_DECL)
71748                                         DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld",
71749                                                              (long) comp_ctx->curr_func.is_strict, (long) 1));
71750                                         comp_ctx->curr_func.is_strict = 1;
71751 #else
71752                                         DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring"));
71753 #endif
71754                                 } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 &&
71755                                            DUK_STRCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail") == 0) {
71756                                         DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld",
71757                                                              (long) comp_ctx->curr_func.is_notail, (long) 1));
71758                                         comp_ctx->curr_func.is_notail = 1;
71759                                 } else {
71760                                         DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
71761                                                            "directive prologue", (duk_hobject *) h_dir));
71762                                 }
71763                         }
71764                 } else {
71765                         DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
71766                                              "prologue terminated if still active"));
71767                 }
71768
71769                 stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM;
71770         }
71771         }  /* end switch (tok) */
71772
71773         /*
71774          *  Statement value handling.
71775          *
71776          *  Global code and eval code has an implicit return value
71777          *  which comes from the last statement with a value
71778          *  (technically a non-"empty" continuation, which is
71779          *  different from an empty statement).
71780          *
71781          *  Since we don't know whether a later statement will
71782          *  override the value of the current statement, we need
71783          *  to coerce the statement value to a register allocated
71784          *  for implicit return values.  In other cases we need
71785          *  to coerce the statement value to a plain value to get
71786          *  any side effects out (consider e.g. "foo.bar;").
71787          */
71788
71789         /* XXX: what about statements which leave a half-cooked value in 'res'
71790          * but have no stmt value?  Any such statements?
71791          */
71792
71793         if (stmt_flags & DUK__HAS_VAL) {
71794                 duk_regconst_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
71795                 if (reg_stmt_value >= 0) {
71796                         duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
71797                 } else {
71798                         duk__ivalue_toplain_ignore(comp_ctx, res);
71799                 }
71800         } else {
71801                 ;
71802         }
71803
71804         /*
71805          *  Statement terminator check, including automatic semicolon
71806          *  handling.  After this step, 'curr_tok' should be the first
71807          *  token after a possible statement terminator.
71808          */
71809
71810         if (stmt_flags & DUK__HAS_TERM) {
71811                 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) {
71812                         DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement"));
71813                         duk__advance(comp_ctx);
71814                 } else {
71815                         if (comp_ctx->curr_token.allow_auto_semi) {
71816                                 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement"));
71817                         } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) {
71818                                 /* XXX: make this lenience dependent on flags or strictness? */
71819                                 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility "
71820                                                      "even though no lineterm present before next token)"));
71821                         } else {
71822                                 DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT);
71823                                 DUK_WO_NORETURN(return;);
71824                         }
71825                 }
71826         } else {
71827                 DUK_DDD(DUK_DDDPRINT("statement has no terminator"));
71828         }
71829
71830         /*
71831          *  Directive prologue tracking.
71832          */
71833
71834         if (stmt_flags & DUK__STILL_PROLOGUE) {
71835                 DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue"));
71836                 comp_ctx->curr_func.in_directive_prologue = 1;
71837         }
71838
71839         /*
71840          *  Cleanups (all statement parsing flows through here).
71841          *
71842          *  Pop label site and reset labels.  Reset 'next temp' to value at
71843          *  entry to reuse temps.
71844          */
71845
71846         if (label_id >= 0) {
71847                 duk__emit_bc(comp_ctx,
71848                              DUK_OP_ENDLABEL,
71849                              (duk_regconst_t) label_id);
71850         }
71851
71852         DUK__SETTEMP(comp_ctx, temp_at_entry);
71853
71854         duk__reset_labels_to_length(comp_ctx, labels_len_at_entry);
71855
71856         /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */
71857
71858         DUK__RECURSION_DECREASE(comp_ctx, thr);
71859 }
71860
71861 /*
71862  *  Parse a statement list.
71863  *
71864  *  Handles automatic semicolon insertion and implicit return value.
71865  *
71866  *  Upon entry, 'curr_tok' should contain the first token of the first
71867  *  statement (parsed in the "allow regexp literal" mode).  Upon exit,
71868  *  'curr_tok' contains the token following the statement list terminator
71869  *  (EOF or closing brace).
71870  */
71871
71872 DUK_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) {
71873         duk_hthread *thr = comp_ctx->thr;
71874         duk_ivalue res_alloc;
71875         duk_ivalue *res = &res_alloc;
71876
71877         /* Setup state.  Initial ivalue is 'undefined'. */
71878
71879         duk_require_stack(thr, DUK__PARSE_STATEMENTS_SLOTS);
71880
71881         /* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
71882          * intermediate values suffice for parsing of each function.  Nesting is needed
71883          * for nested functions (which may occur inside expressions).
71884          */
71885
71886         duk_memzero(&res_alloc, sizeof(res_alloc));
71887         res->t = DUK_IVAL_PLAIN;
71888         res->x1.t = DUK_ISPEC_VALUE;
71889         res->x1.valstack_idx = duk_get_top(thr);
71890         res->x2.valstack_idx = res->x1.valstack_idx + 1;
71891         duk_push_undefined(thr);
71892         duk_push_undefined(thr);
71893
71894         /* Parse statements until a closing token (EOF or '}') is found. */
71895
71896         for (;;) {
71897                 /* Check whether statement list ends. */
71898
71899                 if (expect_eof) {
71900                         if (comp_ctx->curr_token.t == DUK_TOK_EOF) {
71901                                 break;
71902                         }
71903                 } else {
71904                         if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
71905                                 break;
71906                         }
71907                 }
71908
71909                 /* Check statement type based on the first token type.
71910                  *
71911                  * Note: expression parsing helpers expect 'curr_tok' to
71912                  * contain the first token of the expression upon entry.
71913                  */
71914
71915                 DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx->curr_token.t));
71916
71917                 duk__parse_stmt(comp_ctx, res, allow_source_elem);
71918         }
71919
71920         /* RegExp is allowed / not allowed depending on context.  For function
71921          * declarations RegExp is allowed because it follows a function
71922          * declaration statement and may appear as part of the next statement.
71923          * For function expressions RegExp is not allowed, and it's possible
71924          * to do something like '(function () {} / 123)'.
71925          */
71926         if (regexp_after) {
71927                 comp_ctx->curr_func.allow_regexp_in_adv = 1;
71928         }
71929         duk__advance(comp_ctx);
71930
71931         /* Tear down state. */
71932
71933         duk_pop_2(thr);
71934 }
71935
71936 /*
71937  *  Declaration binding instantiation conceptually happens when calling a
71938  *  function; for us it essentially means that function prologue.  The
71939  *  conceptual process is described in E5 Section 10.5.
71940  *
71941  *  We need to keep track of all encountered identifiers to (1) create an
71942  *  identifier-to-register map ("varmap"); and (2) detect duplicate
71943  *  declarations.  Identifiers which are not bound to registers still need
71944  *  to be tracked for detecting duplicates.  Currently such identifiers
71945  *  are put into the varmap with a 'null' value, which is later cleaned up.
71946  *
71947  *  To support functions with a large number of variable and function
71948  *  declarations, registers are not allocated beyond a certain limit;
71949  *  after that limit, variables and functions need slow path access.
71950  *  Arguments are currently always register bound, which imposes a hard
71951  *  (and relatively small) argument count limit.
71952  *
71953  *  Some bindings in E5 are not configurable (= deletable) and almost all
71954  *  are mutable (writable).  Exceptions are:
71955  *
71956  *    - The 'arguments' binding, established only if no shadowing argument
71957  *      or function declaration exists.  We handle 'arguments' creation
71958  *      and binding through an explicit slow path environment record.
71959  *
71960  *    - The "name" binding for a named function expression.  This is also
71961  *      handled through an explicit slow path environment record.
71962  */
71963
71964 /* XXX: add support for variables to not be register bound always, to
71965  * handle cases with a very large number of variables?
71966  */
71967
71968 DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_regconst_t *out_stmt_value_reg) {
71969         duk_hthread *thr = comp_ctx->thr;
71970         duk_hstring *h_name;
71971         duk_bool_t configurable_bindings;
71972         duk_uarridx_t num_args;
71973         duk_uarridx_t num_decls;
71974         duk_regconst_t rc_name;
71975         duk_small_uint_t declvar_flags;
71976         duk_uarridx_t i;
71977 #if defined(DUK_USE_ASSERTIONS)
71978         duk_idx_t entry_top;
71979 #endif
71980
71981 #if defined(DUK_USE_ASSERTIONS)
71982         entry_top = duk_get_top(thr);
71983 #endif
71984
71985         /*
71986          *  Preliminaries
71987          */
71988
71989         configurable_bindings = comp_ctx->curr_func.is_eval;
71990         DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings));
71991
71992         /* varmap is already in comp_ctx->curr_func.varmap_idx */
71993
71994         /*
71995          *  Function formal arguments, always bound to registers
71996          *  (there's no support for shuffling them now).
71997          */
71998
71999         num_args = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx);
72000         DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args));
72001         /* XXX: check num_args */
72002
72003         for (i = 0; i < num_args; i++) {
72004                 duk_get_prop_index(thr, comp_ctx->curr_func.argnames_idx, i);
72005                 h_name = duk_known_hstring(thr, -1);
72006
72007                 if (comp_ctx->curr_func.is_strict) {
72008                         if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
72009                                 DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
72010                                 goto error_argname;
72011                         }
72012                         duk_dup_top(thr);
72013                         if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
72014                                 DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
72015                                 goto error_argname;
72016                         }
72017
72018                         /* Ensure argument name is not a reserved word in current
72019                          * (final) strictness.  Formal argument parsing may not
72020                          * catch reserved names if strictness changes during
72021                          * parsing.
72022                          *
72023                          * We only need to do this in strict mode because non-strict
72024                          * keyword are always detected in formal argument parsing.
72025                          */
72026
72027                         if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) {
72028                                 goto error_argname;
72029                         }
72030                 }
72031
72032                 /* overwrite any previous binding of the same name; the effect is
72033                  * that last argument of a certain name wins.
72034                  */
72035
72036                 /* only functions can have arguments */
72037                 DUK_ASSERT(comp_ctx->curr_func.is_function);
72038                 duk_push_uarridx(thr, i);  /* -> [ ... name index ] */
72039                 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
72040
72041                 /* no code needs to be emitted, the regs already have values */
72042         }
72043
72044         /* use temp_next for tracking register allocations */
72045         DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_regconst_t) num_args);
72046
72047         /*
72048          *  After arguments, allocate special registers (like shuffling temps)
72049          */
72050
72051         if (out_stmt_value_reg) {
72052                 *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
72053         }
72054         if (comp_ctx->curr_func.needs_shuffle) {
72055                 duk_regconst_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
72056                 comp_ctx->curr_func.shuffle1 = shuffle_base;
72057                 comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
72058                 comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
72059                 DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld",
72060                                  (long) comp_ctx->curr_func.shuffle1,
72061                                  (long) comp_ctx->curr_func.shuffle2,
72062                                  (long) comp_ctx->curr_func.shuffle3));
72063         }
72064         if (comp_ctx->curr_func.temp_next > 0x100) {
72065                 DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld", (long) comp_ctx->curr_func.temp_next));
72066                 goto error_outofregs;
72067         }
72068
72069         /*
72070          *  Function declarations
72071          */
72072
72073         num_decls = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.decls_idx);
72074         DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
72075                              (long) num_decls,
72076                              (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.decls_idx)));
72077         for (i = 0; i < num_decls; i += 2) {
72078                 duk_int_t decl_type;
72079                 duk_int_t fnum;
72080
72081                 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1);  /* decl type */
72082                 decl_type = duk_to_int(thr, -1);
72083                 fnum = decl_type >> 8;  /* XXX: macros */
72084                 decl_type = decl_type & 0xff;
72085                 duk_pop(thr);
72086
72087                 if (decl_type != DUK_DECL_TYPE_FUNC) {
72088                         continue;
72089                 }
72090
72091                 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i);  /* decl name */
72092
72093                 /* XXX: spilling */
72094                 if (comp_ctx->curr_func.is_function) {
72095                         duk_regconst_t reg_bind;
72096                         duk_dup_top(thr);
72097                         if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
72098                                 /* shadowed; update value */
72099                                 duk_dup_top(thr);
72100                                 duk_get_prop(thr, comp_ctx->curr_func.varmap_idx);
72101                                 reg_bind = duk_to_int(thr, -1);  /* [ ... name reg_bind ] */
72102                                 duk__emit_a_bc(comp_ctx,
72103                                                DUK_OP_CLOSURE,
72104                                                reg_bind,
72105                                                (duk_regconst_t) fnum);
72106                         } else {
72107                                 /* function: always register bound */
72108                                 reg_bind = DUK__ALLOCTEMP(comp_ctx);
72109                                 duk__emit_a_bc(comp_ctx,
72110                                                DUK_OP_CLOSURE,
72111                                                reg_bind,
72112                                                (duk_regconst_t) fnum);
72113                                 duk_push_int(thr, (duk_int_t) reg_bind);
72114                         }
72115                 } else {
72116                         /* Function declaration for global/eval code is emitted even
72117                          * for duplicates, because of E5 Section 10.5, step 5.e of
72118                          * E5.1 (special behavior for variable bound to global object).
72119                          *
72120                          * DECLVAR will not re-declare a variable as such, but will
72121                          * update the binding value.
72122                          */
72123
72124                         duk_regconst_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
72125                         duk_dup_top(thr);
72126                         rc_name = duk__getconst(comp_ctx);
72127                         duk_push_null(thr);
72128
72129                         duk__emit_a_bc(comp_ctx,
72130                                        DUK_OP_CLOSURE,
72131                                        reg_temp,
72132                                        (duk_regconst_t) fnum);
72133
72134                         declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
72135                                         DUK_PROPDESC_FLAG_ENUMERABLE |
72136                                         DUK_BC_DECLVAR_FLAG_FUNC_DECL;
72137
72138                         if (configurable_bindings) {
72139                                 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
72140                         }
72141
72142                         duk__emit_a_b_c(comp_ctx,
72143                                         DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
72144                                         (duk_regconst_t) declvar_flags /*flags*/,
72145                                         rc_name /*name*/,
72146                                         reg_temp /*value*/);
72147
72148                         DUK__SETTEMP(comp_ctx, reg_temp);  /* forget temp */
72149                 }
72150
72151                 DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
72152                                      (duk_tval *) duk_get_tval(thr, -2),
72153                                      (duk_tval *) duk_get_tval(thr, -1)));
72154
72155 #if defined(DUK_USE_FASTINT)
72156                 DUK_ASSERT(DUK_TVAL_IS_NULL(duk_get_tval(thr, -1)) || DUK_TVAL_IS_FASTINT(duk_get_tval(thr, -1)));
72157 #endif
72158                 duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);  /* [ ... name reg/null ] -> [ ... ] */
72159         }
72160
72161         /*
72162          *  'arguments' binding is special; if a shadowing argument or
72163          *  function declaration exists, an arguments object will
72164          *  definitely not be needed, regardless of whether the identifier
72165          *  'arguments' is referenced inside the function body.
72166          */
72167
72168         if (duk_has_prop_stridx(thr, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
72169                 DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
72170                                      "-> arguments object creation can be skipped"));
72171                 comp_ctx->curr_func.is_arguments_shadowed = 1;
72172         }
72173
72174         /*
72175          *  Variable declarations.
72176          *
72177          *  Unlike function declarations, variable declaration values don't get
72178          *  assigned on entry.  If a binding of the same name already exists, just
72179          *  ignore it silently.
72180          */
72181
72182         for (i = 0; i < num_decls; i += 2) {
72183                 duk_int_t decl_type;
72184
72185                 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i + 1);  /* decl type */
72186                 decl_type = duk_to_int(thr, -1);
72187                 decl_type = decl_type & 0xff;
72188                 duk_pop(thr);
72189
72190                 if (decl_type != DUK_DECL_TYPE_VAR) {
72191                         continue;
72192                 }
72193
72194                 duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i);  /* decl name */
72195
72196                 if (duk_has_prop(thr, comp_ctx->curr_func.varmap_idx)) {
72197                         /* shadowed, ignore */
72198                 } else {
72199                         duk_get_prop_index(thr, comp_ctx->curr_func.decls_idx, i);  /* decl name */
72200                         h_name = duk_known_hstring(thr, -1);
72201
72202                         if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
72203                             !comp_ctx->curr_func.is_arguments_shadowed) {
72204                                 /* E5 Section steps 7-8 */
72205                                 DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
72206                                                      "but appears as a variable declaration -> treat as "
72207                                                      "a no-op for variable declaration purposes"));
72208                                 duk_pop(thr);
72209                                 continue;
72210                         }
72211
72212                         /* XXX: spilling */
72213                         if (comp_ctx->curr_func.is_function) {
72214                                 duk_regconst_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
72215                                 /* no need to init reg, it will be undefined on entry */
72216                                 duk_push_int(thr, (duk_int_t) reg_bind);
72217                         } else {
72218                                 duk_dup_top(thr);
72219                                 rc_name = duk__getconst(comp_ctx);
72220                                 duk_push_null(thr);
72221
72222                                 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
72223                                                 DUK_PROPDESC_FLAG_ENUMERABLE;
72224                                 if (configurable_bindings) {
72225                                         declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
72226                                 }
72227
72228                                 duk__emit_a_b_c(comp_ctx,
72229                                                 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
72230                                                 (duk_regconst_t) declvar_flags /*flags*/,
72231                                                 rc_name /*name*/,
72232                                                 0 /*value*/);
72233                         }
72234
72235                         duk_put_prop(thr, comp_ctx->curr_func.varmap_idx);  /* [ ... name reg/null ] -> [ ... ] */
72236                 }
72237         }
72238
72239         /*
72240          *  Wrap up
72241          */
72242
72243         DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
72244                              (duk_tval *) duk_get_tval(thr, comp_ctx->curr_func.varmap_idx),
72245                              (long) comp_ctx->curr_func.is_arguments_shadowed));
72246
72247         DUK_ASSERT_TOP(thr, entry_top);
72248         return;
72249
72250  error_outofregs:
72251         DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT);
72252         DUK_WO_NORETURN(return;);
72253
72254  error_argname:
72255         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME);
72256         DUK_WO_NORETURN(return;);
72257 }
72258
72259 /*
72260  *  Parse a function-body-like expression (FunctionBody or Program
72261  *  in E5 grammar) using a two-pass parse.  The productions appear
72262  *  in the following contexts:
72263  *
72264  *    - function expression
72265  *    - function statement
72266  *    - function declaration
72267  *    - getter in object literal
72268  *    - setter in object literal
72269  *    - global code
72270  *    - eval code
72271  *    - Function constructor body
72272  *
72273  *  This function only parses the statement list of the body; the argument
72274  *  list and possible function name must be initialized by the caller.
72275  *  For instance, for Function constructor, the argument names are originally
72276  *  on the value stack.  The parsing of statements ends either at an EOF or
72277  *  a closing brace; this is controlled by an input flag.
72278  *
72279  *  Note that there are many differences affecting parsing and even code
72280  *  generation:
72281  *
72282  *    - Global and eval code have an implicit return value generated
72283  *      by the last statement; function code does not
72284  *
72285  *    - Global code, eval code, and Function constructor body end in
72286  *      an EOF, other bodies in a closing brace ('}')
72287  *
72288  *  Upon entry, 'curr_tok' is ignored and the function will pull in the
72289  *  first token on its own.  Upon exit, 'curr_tok' is the terminating
72290  *  token (EOF or closing brace).
72291  */
72292
72293 DUK_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) {
72294         duk_compiler_func *func;
72295         duk_hthread *thr;
72296         duk_regconst_t reg_stmt_value = -1;
72297         duk_lexer_point lex_pt;
72298         duk_regconst_t temp_first;
72299         duk_small_int_t compile_round = 1;
72300
72301         DUK_ASSERT(comp_ctx != NULL);
72302
72303         thr = comp_ctx->thr;
72304         DUK_ASSERT(thr != NULL);
72305
72306         func = &comp_ctx->curr_func;
72307         DUK_ASSERT(func != NULL);
72308
72309         DUK__RECURSION_INCREASE(comp_ctx, thr);
72310
72311         duk_require_stack(thr, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
72312
72313         /*
72314          *  Store lexer position for a later rewind
72315          */
72316
72317         DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt);
72318
72319         /*
72320          *  Program code (global and eval code) has an implicit return value
72321          *  from the last statement value (e.g. eval("1; 2+3;") returns 3).
72322          *  This is not the case with functions.  If implicit statement return
72323          *  value is requested, all statements are coerced to a register
72324          *  allocated here, and used in the implicit return statement below.
72325          */
72326
72327         /* XXX: this is pointless here because pass 1 is throw-away */
72328         if (implicit_return_value) {
72329                 reg_stmt_value = DUK__ALLOCTEMP(comp_ctx);
72330
72331                 /* If an implicit return value is needed by caller, it must be
72332                  * initialized to 'undefined' because we don't know whether any
72333                  * non-empty (where "empty" is a continuation type, and different
72334                  * from an empty statement) statements will be executed.
72335                  *
72336                  * However, since 1st pass is a throwaway one, no need to emit
72337                  * it here.
72338                  */
72339 #if 0
72340                 duk__emit_bc(comp_ctx,
72341                              DUK_OP_LDUNDEF,
72342                              0);
72343 #endif
72344         }
72345
72346         /*
72347          *  First pass.
72348          *
72349          *  Gather variable/function declarations needed for second pass.
72350          *  Code generated is dummy and discarded.
72351          */
72352
72353         func->in_directive_prologue = 1;
72354         func->in_scanning = 1;
72355         func->may_direct_eval = 0;
72356         func->id_access_arguments = 0;
72357         func->id_access_slow = 0;
72358         func->id_access_slow_own = 0;
72359         func->reg_stmt_value = reg_stmt_value;
72360 #if defined(DUK_USE_DEBUGGER_SUPPORT)
72361         func->min_line = DUK_INT_MAX;
72362         func->max_line = 0;
72363 #endif
72364
72365         /* duk__parse_stmts() expects curr_tok to be set; parse in "allow
72366          * regexp literal" mode with current strictness.
72367          */
72368         if (expect_token >= 0) {
72369                 /* Eating a left curly; regexp mode is allowed by left curly
72370                  * based on duk__token_lbp[] automatically.
72371                  */
72372                 DUK_ASSERT(expect_token == DUK_TOK_LCURLY);
72373                 duk__update_lineinfo_currtoken(comp_ctx);
72374                 duk__advance_expect(comp_ctx, expect_token);
72375         } else {
72376                 /* Need to set curr_token.t because lexing regexp mode depends on current
72377                  * token type.  Zero value causes "allow regexp" mode.
72378                  */
72379                 comp_ctx->curr_token.t = 0;
72380                 duk__advance(comp_ctx);
72381         }
72382
72383         DUK_DDD(DUK_DDDPRINT("begin 1st pass"));
72384         duk__parse_stmts(comp_ctx,
72385                          1,             /* allow source elements */
72386                          expect_eof,    /* expect EOF instead of } */
72387                          regexp_after); /* regexp after */
72388         DUK_DDD(DUK_DDDPRINT("end 1st pass"));
72389
72390         /*
72391          *  Second (and possibly third) pass.
72392          *
72393          *  Generate actual code.  In most cases the need for shuffle
72394          *  registers is detected during pass 1, but in some corner cases
72395          *  we'll only detect it during pass 2 and a third pass is then
72396          *  needed (see GH-115).
72397          */
72398
72399         for (;;) {
72400                 duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle;
72401                 compile_round++;
72402
72403                 /*
72404                  *  Rewind lexer.
72405                  *
72406                  *  duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
72407                  *  literal" mode with current strictness.
72408                  *
72409                  *  curr_token line number info should be initialized for pass 2 before
72410                  *  generating prologue, to ensure prologue bytecode gets nice line numbers.
72411                  */
72412
72413                 DUK_DDD(DUK_DDDPRINT("rewind lexer"));
72414                 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
72415                 comp_ctx->curr_token.t = 0;  /* this is needed for regexp mode */
72416                 comp_ctx->curr_token.start_line = 0;  /* needed for line number tracking (becomes prev_token.start_line) */
72417                 duk__advance(comp_ctx);
72418
72419                 /*
72420                  *  Reset function state and perform register allocation, which creates
72421                  *  'varmap' for second pass.  Function prologue for variable declarations,
72422                  *  binding value initializations etc is emitted as a by-product.
72423                  *
72424                  *  Strict mode restrictions for duplicate and invalid argument
72425                  *  names are checked here now that we know whether the function
72426                  *  is actually strict.  See: test-dev-strict-mode-boundary.js.
72427                  *
72428                  *  Inner functions are compiled during pass 1 and are not reset.
72429                  */
72430
72431                 duk__reset_func_for_pass2(comp_ctx);
72432                 func->in_directive_prologue = 1;
72433                 func->in_scanning = 0;
72434
72435                 /* must be able to emit code, alloc consts, etc. */
72436
72437                 duk__init_varmap_and_prologue_for_pass2(comp_ctx,
72438                                                         (implicit_return_value ? &reg_stmt_value : NULL));
72439                 func->reg_stmt_value = reg_stmt_value;
72440
72441                 temp_first = DUK__GETTEMP(comp_ctx);
72442
72443                 func->temp_first = temp_first;
72444                 func->temp_next = temp_first;
72445                 func->stmt_next = 0;
72446                 func->label_next = 0;
72447
72448                 /* XXX: init or assert catch depth etc -- all values */
72449                 func->id_access_arguments = 0;
72450                 func->id_access_slow = 0;
72451                 func->id_access_slow_own = 0;
72452
72453                 /*
72454                  *  Check function name validity now that we know strictness.
72455                  *  This only applies to function declarations and expressions,
72456                  *  not setter/getter name.
72457                  *
72458                  *  See: test-dev-strict-mode-boundary.js
72459                  */
72460
72461                 if (func->is_function && !func->is_setget && func->h_name != NULL) {
72462                         if (func->is_strict) {
72463                                 if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) {
72464                                         DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode"));
72465                                         goto error_funcname;
72466                                 }
72467                                 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
72468                                         DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode"));
72469                                         goto error_funcname;
72470                                 }
72471                         } else {
72472                                 if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) &&
72473                                     !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
72474                                         DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode"));
72475                                         goto error_funcname;
72476                                 }
72477                         }
72478                 }
72479
72480                 /*
72481                  *  Second pass parsing.
72482                  */
72483
72484                 if (implicit_return_value) {
72485                         /* Default implicit return value. */
72486                         duk__emit_bc(comp_ctx,
72487                                      DUK_OP_LDUNDEF,
72488                                      0);
72489                 }
72490
72491                 DUK_DDD(DUK_DDDPRINT("begin 2nd pass"));
72492                 duk__parse_stmts(comp_ctx,
72493                                  1,             /* allow source elements */
72494                                  expect_eof,    /* expect EOF instead of } */
72495                                  regexp_after); /* regexp after */
72496                 DUK_DDD(DUK_DDDPRINT("end 2nd pass"));
72497
72498                 duk__update_lineinfo_currtoken(comp_ctx);
72499
72500                 if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) {
72501                         /* Shuffle decision not changed. */
72502                         break;
72503                 }
72504                 if (compile_round >= 3) {
72505                         /* Should never happen but avoid infinite loop just in case. */
72506                         DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen"));
72507                         DUK_ERROR_INTERNAL(thr);
72508                         DUK_WO_NORETURN(return;);
72509                 }
72510                 DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round));
72511         }
72512
72513         /*
72514          *  Emit a final RETURN.
72515          *
72516          *  It would be nice to avoid emitting an unnecessary "return" opcode
72517          *  if the current PC is not reachable.  However, this cannot be reliably
72518          *  detected; even if the previous instruction is an unconditional jump,
72519          *  there may be a previous jump which jumps to current PC (which is the
72520          *  case for iteration and conditional statements, for instance).
72521          */
72522
72523         /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts();
72524          * we could avoid the last RETURN if we could ensure there is no way to get here
72525          * (directly or via a jump)
72526          */
72527
72528         DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);
72529         if (reg_stmt_value >= 0) {
72530                 DUK_ASSERT(DUK__ISREG(reg_stmt_value));
72531                 duk__emit_bc(comp_ctx, DUK_OP_RETREG, reg_stmt_value /*reg*/);
72532         } else {
72533                 duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
72534         }
72535
72536         /*
72537          *  Peephole optimize JUMP chains.
72538          */
72539
72540         duk__peephole_optimize_bytecode(comp_ctx);
72541
72542         /*
72543          *  comp_ctx->curr_func is now ready to be converted into an actual
72544          *  function template.
72545          */
72546
72547         DUK__RECURSION_DECREASE(comp_ctx, thr);
72548         return;
72549
72550  error_funcname:
72551         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME);
72552         DUK_WO_NORETURN(return;);
72553 }
72554
72555 /*
72556  *  Parse a function-like expression:
72557  *
72558  *    - function expression
72559  *    - function declaration
72560  *    - function statement (non-standard)
72561  *    - setter/getter
72562  *
72563  *  Adds the function to comp_ctx->curr_func function table and returns the
72564  *  function number.
72565  *
72566  *  On entry, curr_token points to:
72567  *
72568  *    - the token after 'function' for function expression/declaration/statement
72569  *    - the token after 'set' or 'get' for setter/getter
72570  */
72571
72572 /* Parse formals. */
72573 DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
72574         duk_hthread *thr = comp_ctx->thr;
72575         duk_bool_t first = 1;
72576         duk_uarridx_t n;
72577
72578         for (;;) {
72579                 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
72580                         break;
72581                 }
72582
72583                 if (first) {
72584                         /* no comma */
72585                         first = 0;
72586                 } else {
72587                         duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
72588                 }
72589
72590                 /* Note: when parsing a formal list in non-strict context, e.g.
72591                  * "implements" is parsed as an identifier.  When the function is
72592                  * later detected to be strict, the argument list must be rechecked
72593                  * against a larger set of reserved words (that of strict mode).
72594                  * This is handled by duk__parse_func_body().  Here we recognize
72595                  * whatever tokens are considered reserved in current strictness
72596                  * (which is not always enough).
72597                  */
72598
72599                 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
72600                         DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
72601                         DUK_WO_NORETURN(return;);
72602                 }
72603                 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
72604                 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
72605                 DUK_DDD(DUK_DDDPRINT("formal argument: %!O",
72606                                      (duk_heaphdr *) comp_ctx->curr_token.str1));
72607
72608                 /* XXX: append primitive */
72609                 duk_push_hstring(thr, comp_ctx->curr_token.str1);
72610                 n = (duk_uarridx_t) duk_get_length(thr, comp_ctx->curr_func.argnames_idx);
72611                 duk_put_prop_index(thr, comp_ctx->curr_func.argnames_idx, n);
72612
72613                 duk__advance(comp_ctx);  /* eat identifier */
72614         }
72615 }
72616
72617 /* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is
72618  * correctly set up.  Assumes that curr_token is just after 'function' (or
72619  * 'set'/'get' etc).
72620  */
72621 DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
72622         duk_hthread *thr = comp_ctx->thr;
72623         duk_token *tok;
72624         duk_bool_t no_advance;
72625
72626         DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
72627         DUK_ASSERT(comp_ctx->curr_func.is_function == 1);
72628         DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
72629         DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
72630         DUK_ASSERT(comp_ctx->curr_func.is_setget == ((flags & DUK__FUNC_FLAG_GETSET) != 0));
72631
72632         duk__update_lineinfo_currtoken(comp_ctx);
72633
72634         /*
72635          *  Function name (if any)
72636          *
72637          *  We don't check for prohibited names here, because we don't
72638          *  yet know whether the function will be strict.  Function body
72639          *  parsing handles this retroactively.
72640          *
72641          *  For function expressions and declarations function name must
72642          *  be an Identifer (excludes reserved words).  For setter/getter
72643          *  it is a PropertyName which allows reserved words and also
72644          *  strings and numbers (e.g. "{ get 1() { ... } }").
72645          *
72646          *  Function parsing may start either from prev_token or curr_token
72647          *  (object literal method definition uses prev_token for example).
72648          *  This is dealt with for the initial token.
72649          */
72650
72651         no_advance = (flags & DUK__FUNC_FLAG_USE_PREVTOKEN);
72652         if (no_advance) {
72653                 tok = &comp_ctx->prev_token;
72654         } else {
72655                 tok = &comp_ctx->curr_token;
72656         }
72657
72658         if (flags & DUK__FUNC_FLAG_GETSET) {
72659                 /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
72660                 if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t == DUK_TOK_STRING) {
72661                         duk_push_hstring(thr, tok->str1);       /* keep in valstack */
72662                 } else if (tok->t == DUK_TOK_NUMBER) {
72663                         duk_push_number(thr, tok->num);
72664                         duk_to_string(thr, -1);
72665                 } else {
72666                         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
72667                         DUK_WO_NORETURN(return;);
72668                 }
72669                 comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1);  /* borrowed reference */
72670         } else {
72671                 /* Function name is an Identifier (not IdentifierName), but we get
72672                  * the raw name (not recognizing keywords) here and perform the name
72673                  * checks only after pass 1.
72674                  */
72675                 if (tok->t_nores == DUK_TOK_IDENTIFIER) {
72676                         duk_push_hstring(thr, tok->str1);       /* keep in valstack */
72677                         comp_ctx->curr_func.h_name = duk_known_hstring(thr, -1);  /* borrowed reference */
72678                 } else {
72679                         /* valstack will be unbalanced, which is OK */
72680                         DUK_ASSERT((flags & DUK__FUNC_FLAG_GETSET) == 0);
72681                         DUK_ASSERT(comp_ctx->curr_func.h_name == NULL);
72682                         no_advance = 1;
72683                         if (flags & DUK__FUNC_FLAG_DECL) {
72684                                 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED);
72685                                 DUK_WO_NORETURN(return;);
72686                         }
72687                 }
72688         }
72689
72690         DUK_DD(DUK_DDPRINT("function name: %!O",
72691                            (duk_heaphdr *) comp_ctx->curr_func.h_name));
72692
72693         if (!no_advance) {
72694                 duk__advance(comp_ctx);
72695         }
72696
72697         /*
72698          *  Formal argument list
72699          *
72700          *  We don't check for prohibited names or for duplicate argument
72701          *  names here, becase we don't yet know whether the function will
72702          *  be strict.  Function body parsing handles this retroactively.
72703          */
72704
72705         duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
72706
72707         duk__parse_func_formals(comp_ctx);
72708
72709         DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN);
72710         duk__advance(comp_ctx);
72711
72712         /*
72713          *  Parse function body
72714          */
72715
72716         duk__parse_func_body(comp_ctx,
72717                              0,   /* expect_eof */
72718                              0,   /* implicit_return_value */
72719                              flags & DUK__FUNC_FLAG_DECL, /* regexp_after */
72720                              DUK_TOK_LCURLY);  /* expect_token */
72721
72722         /*
72723          *  Convert duk_compiler_func to a function template and add it
72724          *  to the parent function table.
72725          */
72726
72727         duk__convert_to_func_template(comp_ctx);  /* -> [ ... func ] */
72728 }
72729
72730 /* Parse an inner function, adding the function template to the current function's
72731  * function table.  Return a function number to be used by the outer function.
72732  *
72733  * Avoiding O(depth^2) inner function parsing is handled here.  On the first pass,
72734  * compile and register the function normally into the 'funcs' array, also recording
72735  * a lexer point (offset/line) to the closing brace of the function.  On the second
72736  * pass, skip the function and return the same 'fnum' as on the first pass by using
72737  * a running counter.
72738  *
72739  * An unfortunate side effect of this is that when parsing the inner function, almost
72740  * nothing is known of the outer function, i.e. the inner function's scope.  We don't
72741  * need that information at the moment, but it would allow some optimizations if it
72742  * were used.
72743  */
72744 DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
72745         duk_hthread *thr = comp_ctx->thr;
72746         duk_compiler_func old_func;
72747         duk_idx_t entry_top;
72748         duk_int_t fnum;
72749
72750         /*
72751          *  On second pass, skip the function.
72752          */
72753
72754         if (!comp_ctx->curr_func.in_scanning) {
72755                 duk_lexer_point lex_pt;
72756
72757                 fnum = comp_ctx->curr_func.fnum_next++;
72758                 duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
72759                 lex_pt.offset = (duk_size_t) duk_to_uint(thr, -1);
72760                 duk_pop(thr);
72761                 duk_get_prop_index(thr, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
72762                 lex_pt.line = duk_to_int(thr, -1);
72763                 duk_pop(thr);
72764
72765                 DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
72766                                      (long) lex_pt.offset, (long) lex_pt.line));
72767
72768                 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
72769                 comp_ctx->curr_token.t = 0;  /* this is needed for regexp mode */
72770                 comp_ctx->curr_token.start_line = 0;  /* needed for line number tracking (becomes prev_token.start_line) */
72771                 duk__advance(comp_ctx);
72772
72773                 /* RegExp is not allowed after a function expression, e.g. in
72774                  * (function () {} / 123).  A RegExp *is* allowed after a
72775                  * function declaration!
72776                  */
72777                 if (flags & DUK__FUNC_FLAG_DECL) {
72778                         comp_ctx->curr_func.allow_regexp_in_adv = 1;
72779                 }
72780                 duk__advance_expect(comp_ctx, DUK_TOK_RCURLY);
72781
72782                 return fnum;
72783         }
72784
72785         /*
72786          *  On first pass, perform actual parsing.  Remember valstack top on entry
72787          *  to restore it later, and switch to using a new function in comp_ctx.
72788          */
72789
72790         entry_top = duk_get_top(thr);
72791         DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
72792                              (long) entry_top, (long) comp_ctx->curr_token.start_offset));
72793
72794         duk_memcpy(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func));
72795
72796         duk_memzero(&comp_ctx->curr_func, sizeof(duk_compiler_func));
72797         duk__init_func_valstack_slots(comp_ctx);
72798         DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
72799
72800         /* inherit initial strictness from parent */
72801         comp_ctx->curr_func.is_strict = old_func.is_strict;
72802
72803         /* XXX: It might be better to just store the flags into the curr_func
72804          * struct and use them as is without this flag interpretation step
72805          * here.
72806          */
72807         DUK_ASSERT(comp_ctx->curr_func.is_notail == 0);
72808         comp_ctx->curr_func.is_function = 1;
72809         DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
72810         DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
72811         comp_ctx->curr_func.is_setget = ((flags & DUK__FUNC_FLAG_GETSET) != 0);
72812         comp_ctx->curr_func.is_namebinding = !(flags & (DUK__FUNC_FLAG_GETSET |
72813                                                         DUK__FUNC_FLAG_METDEF |
72814                                                         DUK__FUNC_FLAG_DECL));  /* no name binding for: declarations, objlit getset, objlit method def */
72815         comp_ctx->curr_func.is_constructable = !(flags & (DUK__FUNC_FLAG_GETSET |
72816                                                           DUK__FUNC_FLAG_METDEF));  /* not constructable: objlit getset, objlit method def */
72817
72818         /*
72819          *  Parse inner function
72820          */
72821
72822         duk__parse_func_like_raw(comp_ctx, flags);  /* pushes function template */
72823
72824         /* prev_token.start_offset points to the closing brace here; when skipping
72825          * we're going to reparse the closing brace to ensure semicolon insertion
72826          * etc work as expected.
72827          */
72828         DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld",
72829                              (long) comp_ctx->prev_token.start_offset, (long) comp_ctx->curr_token.start_offset));
72830         DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY);
72831
72832         /* XXX: append primitive */
72833         DUK_ASSERT(duk_get_length(thr, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
72834         fnum = old_func.fnum_next++;
72835
72836         if (fnum > DUK__MAX_FUNCS) {
72837                 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT);
72838                 DUK_WO_NORETURN(return 0;);
72839         }
72840
72841         /* array writes autoincrement length */
72842         (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
72843         duk_push_size_t(thr, comp_ctx->prev_token.start_offset);
72844         (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
72845         duk_push_int(thr, comp_ctx->prev_token.start_line);
72846         (void) duk_put_prop_index(thr, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
72847
72848         /*
72849          *  Cleanup: restore original function, restore valstack state.
72850          *
72851          *  Function declaration handling needs the function name to be pushed
72852          *  on the value stack.
72853          */
72854
72855         if (flags & DUK__FUNC_FLAG_PUSHNAME_PASS1) {
72856                 DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
72857                 duk_push_hstring(thr, comp_ctx->curr_func.h_name);
72858                 duk_replace(thr, entry_top);
72859                 duk_set_top(thr, entry_top + 1);
72860         } else {
72861                 duk_set_top(thr, entry_top);
72862         }
72863         duk_memcpy((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
72864
72865         return fnum;
72866 }
72867
72868 /*
72869  *  Compile input string into an executable function template without
72870  *  arguments.
72871  *
72872  *  The string is parsed as the "Program" production of ECMAScript E5.
72873  *  Compilation context can be either global code or eval code (see E5
72874  *  Sections 14 and 15.1.2.1).
72875  *
72876  *  Input stack:  [ ... filename ]
72877  *  Output stack: [ ... func_template ]
72878  */
72879
72880 /* XXX: source code property */
72881
72882 DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_hthread *thr, void *udata) {
72883         duk_hstring *h_filename;
72884         duk__compiler_stkstate *comp_stk;
72885         duk_compiler_ctx *comp_ctx;
72886         duk_lexer_point *lex_pt;
72887         duk_compiler_func *func;
72888         duk_idx_t entry_top;
72889         duk_bool_t is_strict;
72890         duk_bool_t is_eval;
72891         duk_bool_t is_funcexpr;
72892         duk_small_uint_t flags;
72893
72894         DUK_ASSERT(thr != NULL);
72895         DUK_ASSERT(udata != NULL);
72896
72897         /*
72898          *  Arguments check
72899          */
72900
72901         entry_top = duk_get_top(thr);
72902         DUK_ASSERT(entry_top >= 1);
72903
72904         comp_stk = (duk__compiler_stkstate *) udata;
72905         comp_ctx = &comp_stk->comp_ctx_alloc;
72906         lex_pt = &comp_stk->lex_pt_alloc;
72907         DUK_ASSERT(comp_ctx != NULL);
72908         DUK_ASSERT(lex_pt != NULL);
72909
72910         flags = comp_stk->flags;
72911         is_eval = (flags & DUK_COMPILE_EVAL ? 1 : 0);
72912         is_strict = (flags & DUK_COMPILE_STRICT ? 1 : 0);
72913         is_funcexpr = (flags & DUK_COMPILE_FUNCEXPR ? 1 : 0);
72914
72915         h_filename = duk_get_hstring(thr, -1);  /* may be undefined */
72916
72917         /*
72918          *  Init compiler and lexer contexts
72919          */
72920
72921         func = &comp_ctx->curr_func;
72922 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
72923         comp_ctx->thr = NULL;
72924         comp_ctx->h_filename = NULL;
72925         comp_ctx->prev_token.str1 = NULL;
72926         comp_ctx->prev_token.str2 = NULL;
72927         comp_ctx->curr_token.str1 = NULL;
72928         comp_ctx->curr_token.str2 = NULL;
72929 #endif
72930
72931         duk_require_stack(thr, DUK__COMPILE_ENTRY_SLOTS);
72932
72933         duk_push_dynamic_buffer(thr, 0);       /* entry_top + 0 */
72934         duk_push_undefined(thr);               /* entry_top + 1 */
72935         duk_push_undefined(thr);               /* entry_top + 2 */
72936         duk_push_undefined(thr);               /* entry_top + 3 */
72937         duk_push_undefined(thr);               /* entry_top + 4 */
72938
72939         comp_ctx->thr = thr;
72940         comp_ctx->h_filename = h_filename;
72941         comp_ctx->tok11_idx = entry_top + 1;
72942         comp_ctx->tok12_idx = entry_top + 2;
72943         comp_ctx->tok21_idx = entry_top + 3;
72944         comp_ctx->tok22_idx = entry_top + 4;
72945         comp_ctx->recursion_limit = DUK_USE_COMPILER_RECLIMIT;
72946
72947         /* comp_ctx->lex has been pre-initialized by caller: it has been
72948          * zeroed and input/input_length has been set.
72949          */
72950         comp_ctx->lex.thr = thr;
72951         /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */
72952         comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
72953         comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
72954         comp_ctx->lex.buf_idx = entry_top + 0;
72955         comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, entry_top + 0);
72956         DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf));
72957         comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
72958
72959         lex_pt->offset = 0;
72960         lex_pt->line = 1;
72961         DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt);    /* fills window */
72962         comp_ctx->curr_token.start_line = 0;  /* needed for line number tracking (becomes prev_token.start_line) */
72963
72964         /*
72965          *  Initialize function state for a zero-argument function
72966          */
72967
72968         duk__init_func_valstack_slots(comp_ctx);
72969         DUK_ASSERT(func->num_formals == 0);
72970
72971         if (is_funcexpr) {
72972                 /* Name will be filled from function expression, not by caller.
72973                  * This case is used by Function constructor and duk_compile()
72974                  * API with the DUK_COMPILE_FUNCTION option.
72975                  */
72976                 DUK_ASSERT(func->h_name == NULL);
72977         } else {
72978                 duk_push_hstring_stridx(thr, (is_eval ? DUK_STRIDX_EVAL :
72979                                                         DUK_STRIDX_GLOBAL));
72980                 func->h_name = duk_get_hstring(thr, -1);
72981         }
72982
72983         /*
72984          *  Parse a function body or a function-like expression, depending
72985          *  on flags.
72986          */
72987
72988         DUK_ASSERT(func->is_setget == 0);
72989         func->is_strict = (duk_uint8_t) is_strict;
72990         DUK_ASSERT(func->is_notail == 0);
72991
72992         if (is_funcexpr) {
72993                 func->is_function = 1;
72994                 DUK_ASSERT(func->is_eval == 0);
72995                 DUK_ASSERT(func->is_global == 0);
72996                 func->is_namebinding = 1;
72997                 func->is_constructable = 1;
72998
72999                 duk__advance(comp_ctx);  /* init 'curr_token' */
73000                 duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION);
73001                 (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/);
73002         } else {
73003                 DUK_ASSERT(func->is_function == 0);
73004                 DUK_ASSERT(is_eval == 0 || is_eval == 1);
73005                 func->is_eval = (duk_uint8_t) is_eval;
73006                 func->is_global = (duk_uint8_t) !is_eval;
73007                 DUK_ASSERT(func->is_namebinding == 0);
73008                 DUK_ASSERT(func->is_constructable == 0);
73009
73010                 duk__parse_func_body(comp_ctx,
73011                                      1,             /* expect_eof */
73012                                      1,             /* implicit_return_value */
73013                                      1,             /* regexp_after (does not matter) */
73014                                      -1);           /* expect_token */
73015         }
73016
73017         /*
73018          *  Convert duk_compiler_func to a function template
73019          */
73020
73021         duk__convert_to_func_template(comp_ctx);
73022
73023         /*
73024          *  Wrapping duk_safe_call() will mangle the stack, just return stack top
73025          */
73026
73027         /* [ ... filename (temps) func ] */
73028
73029         return 1;
73030 }
73031
73032 DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) {
73033         duk__compiler_stkstate comp_stk;
73034         duk_compiler_ctx *prev_ctx;
73035         duk_ret_t safe_rc;
73036
73037         DUK_ASSERT(thr != NULL);
73038         DUK_ASSERT(src_buffer != NULL);
73039
73040         /* preinitialize lexer state partially */
73041         duk_memzero(&comp_stk, sizeof(comp_stk));
73042         comp_stk.flags = flags;
73043         DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex);
73044         comp_stk.comp_ctx_alloc.lex.input = src_buffer;
73045         comp_stk.comp_ctx_alloc.lex.input_length = src_length;
73046         comp_stk.comp_ctx_alloc.lex.flags = flags;  /* Forward flags directly for now. */
73047
73048         /* [ ... filename ] */
73049
73050         prev_ctx = thr->compile_ctx;
73051         thr->compile_ctx = &comp_stk.comp_ctx_alloc;  /* for duk_error_augment.c */
73052         safe_rc = duk_safe_call(thr, duk__js_compile_raw, (void *) &comp_stk /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
73053         thr->compile_ctx = prev_ctx;  /* must restore reliably before returning */
73054
73055         if (safe_rc != DUK_EXEC_SUCCESS) {
73056                 DUK_D(DUK_DPRINT("compilation failed: %!T", duk_get_tval(thr, -1)));
73057                 (void) duk_throw(thr);
73058                 DUK_WO_NORETURN(return;);
73059         }
73060
73061         /* [ ... template ] */
73062 }
73063
73064 /* automatic undefs */
73065 #undef DUK__ALLOCTEMP
73066 #undef DUK__ALLOCTEMPS
73067 #undef DUK__ALLOW_AUTO_SEMI_ALWAYS
73068 #undef DUK__BC_INITIAL_INSTS
73069 #undef DUK__BP_ADDITIVE
73070 #undef DUK__BP_ASSIGNMENT
73071 #undef DUK__BP_BAND
73072 #undef DUK__BP_BOR
73073 #undef DUK__BP_BXOR
73074 #undef DUK__BP_CALL
73075 #undef DUK__BP_CLOSING
73076 #undef DUK__BP_COMMA
73077 #undef DUK__BP_CONDITIONAL
73078 #undef DUK__BP_EOF
73079 #undef DUK__BP_EQUALITY
73080 #undef DUK__BP_EXPONENTIATION
73081 #undef DUK__BP_FOR_EXPR
73082 #undef DUK__BP_INVALID
73083 #undef DUK__BP_LAND
73084 #undef DUK__BP_LOR
73085 #undef DUK__BP_MEMBER
73086 #undef DUK__BP_MULTIPLICATIVE
73087 #undef DUK__BP_POSTFIX
73088 #undef DUK__BP_RELATIONAL
73089 #undef DUK__BP_SHIFT
73090 #undef DUK__COMPILE_ENTRY_SLOTS
73091 #undef DUK__CONST_MARKER
73092 #undef DUK__DUMP_ISPEC
73093 #undef DUK__DUMP_IVALUE
73094 #undef DUK__EMIT_FLAG_A_IS_SOURCE
73095 #undef DUK__EMIT_FLAG_BC_REGCONST
73096 #undef DUK__EMIT_FLAG_B_IS_TARGET
73097 #undef DUK__EMIT_FLAG_C_IS_TARGET
73098 #undef DUK__EMIT_FLAG_NO_SHUFFLE_A
73099 #undef DUK__EMIT_FLAG_NO_SHUFFLE_B
73100 #undef DUK__EMIT_FLAG_NO_SHUFFLE_C
73101 #undef DUK__EMIT_FLAG_RESERVE_JUMPSLOT
73102 #undef DUK__EXPR_FLAG_ALLOW_EMPTY
73103 #undef DUK__EXPR_FLAG_REJECT_IN
73104 #undef DUK__EXPR_FLAG_REQUIRE_INIT
73105 #undef DUK__EXPR_RBP_MASK
73106 #undef DUK__FUNCTION_BODY_REQUIRE_SLOTS
73107 #undef DUK__FUNCTION_INIT_REQUIRE_SLOTS
73108 #undef DUK__FUNC_FLAG_DECL
73109 #undef DUK__FUNC_FLAG_GETSET
73110 #undef DUK__FUNC_FLAG_METDEF
73111 #undef DUK__FUNC_FLAG_PUSHNAME_PASS1
73112 #undef DUK__FUNC_FLAG_USE_PREVTOKEN
73113 #undef DUK__GETCONST_MAX_CONSTS_CHECK
73114 #undef DUK__GETTEMP
73115 #undef DUK__HAS_TERM
73116 #undef DUK__HAS_VAL
73117 #undef DUK__ISCONST
73118 #undef DUK__ISREG
73119 #undef DUK__ISREG_NOTTEMP
73120 #undef DUK__ISREG_TEMP
73121 #undef DUK__IS_TERMINAL
73122 #undef DUK__IVAL_FLAG_ALLOW_CONST
73123 #undef DUK__IVAL_FLAG_REQUIRE_SHORT
73124 #undef DUK__IVAL_FLAG_REQUIRE_TEMP
73125 #undef DUK__MAX_ARRAY_INIT_VALUES
73126 #undef DUK__MAX_CONSTS
73127 #undef DUK__MAX_FUNCS
73128 #undef DUK__MAX_OBJECT_INIT_PAIRS
73129 #undef DUK__MAX_TEMPS
73130 #undef DUK__MK_LBP
73131 #undef DUK__MK_LBP_FLAGS
73132 #undef DUK__OBJ_LIT_KEY_GET
73133 #undef DUK__OBJ_LIT_KEY_PLAIN
73134 #undef DUK__OBJ_LIT_KEY_SET
73135 #undef DUK__PARSE_EXPR_SLOTS
73136 #undef DUK__PARSE_STATEMENTS_SLOTS
73137 #undef DUK__RECURSION_DECREASE
73138 #undef DUK__RECURSION_INCREASE
73139 #undef DUK__REMOVECONST
73140 #undef DUK__SETTEMP
73141 #undef DUK__SETTEMP_CHECKMAX
73142 #undef DUK__STILL_PROLOGUE
73143 #undef DUK__TOKEN_LBP_BP_MASK
73144 #undef DUK__TOKEN_LBP_FLAG_NO_REGEXP
73145 #undef DUK__TOKEN_LBP_FLAG_TERMINATES
73146 #undef DUK__TOKEN_LBP_FLAG_UNUSED
73147 #undef DUK__TOKEN_LBP_GET_BP
73148 #line 1 "duk_js_executor.c"
73149 /*
73150  *  ECMAScript bytecode executor.
73151  */
73152
73153 /* #include duk_internal.h -> already included */
73154
73155 /*
73156  *  Local declarations.
73157  */
73158
73159 DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act);
73160
73161 /*
73162  *  Misc helpers.
73163  */
73164
73165 /* Forced inline declaration, only applied for performance oriented build. */
73166 #if defined(DUK_USE_EXEC_PREFER_SIZE)
73167 #define DUK__INLINE_PERF
73168 #define DUK__NOINLINE_PERF
73169 #else
73170 #define DUK__INLINE_PERF DUK_ALWAYS_INLINE
73171 #define DUK__NOINLINE_PERF DUK_NOINLINE
73172 #endif
73173
73174 /* Replace value stack top to value at 'tv_ptr'.  Optimize for
73175  * performance by only applying the net refcount change.
73176  */
73177 #define DUK__REPLACE_TO_TVPTR(thr,tv_ptr) do { \
73178                 duk_hthread *duk__thr; \
73179                 duk_tval *duk__tvsrc; \
73180                 duk_tval *duk__tvdst; \
73181                 duk_tval duk__tvtmp; \
73182                 duk__thr = (thr); \
73183                 duk__tvsrc = DUK_GET_TVAL_NEGIDX(duk__thr, -1); \
73184                 duk__tvdst = (tv_ptr); \
73185                 DUK_TVAL_SET_TVAL(&duk__tvtmp, duk__tvdst); \
73186                 DUK_TVAL_SET_TVAL(duk__tvdst, duk__tvsrc); \
73187                 DUK_TVAL_SET_UNDEFINED(duk__tvsrc);  /* value stack init policy */ \
73188                 duk__thr->valstack_top = duk__tvsrc; \
73189                 DUK_TVAL_DECREF(duk__thr, &duk__tvtmp); \
73190         } while (0)
73191
73192 /* XXX: candidate of being an internal shared API call */
73193 #if 0  /* unused */
73194 DUK_LOCAL void duk__push_tvals_incref_only(duk_hthread *thr, duk_tval *tv_src, duk_small_uint_fast_t count) {
73195         duk_tval *tv_dst;
73196         duk_size_t copy_size;
73197         duk_size_t i;
73198
73199         tv_dst = thr->valstack_top;
73200         copy_size = sizeof(duk_tval) * count;
73201         duk_memcpy((void *) tv_dst, (const void *) tv_src, copy_size);
73202         for (i = 0; i < count; i++) {
73203                 DUK_TVAL_INCREF(thr, tv_dst);
73204                 tv_dst++;
73205         }
73206         thr->valstack_top = tv_dst;
73207 }
73208 #endif
73209
73210 /*
73211  *  Arithmetic, binary, and logical helpers.
73212  *
73213  *  Note: there is no opcode for logical AND or logical OR; this is on
73214  *  purpose, because the evalution order semantics for them make such
73215  *  opcodes pretty pointless: short circuiting means they are most
73216  *  comfortably implemented as jumps.  However, a logical NOT opcode
73217  *  is useful.
73218  *
73219  *  Note: careful with duk_tval pointers here: they are potentially
73220  *  invalidated by any DECREF and almost any API call.  It's still
73221  *  preferable to work without making a copy but that's not always
73222  *  possible.
73223  */
73224
73225 DUK_LOCAL DUK__INLINE_PERF duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) {
73226         return (duk_double_t) duk_js_arith_mod((double) d1, (double) d2);
73227 }
73228
73229 #if defined(DUK_USE_ES7_EXP_OPERATOR)
73230 DUK_LOCAL DUK__INLINE_PERF duk_double_t duk__compute_exp(duk_double_t d1, duk_double_t d2) {
73231         return (duk_double_t) duk_js_arith_pow((double) d1, (double) d2);
73232 }
73233 #endif
73234
73235 DUK_LOCAL DUK__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) {
73236         /*
73237          *  Addition operator is different from other arithmetic
73238          *  operations in that it also provides string concatenation.
73239          *  Hence it is implemented separately.
73240          *
73241          *  There is a fast path for number addition.  Other cases go
73242          *  through potentially multiple coercions as described in the
73243          *  E5 specification.  It may be possible to reduce the number
73244          *  of coercions, but this must be done carefully to preserve
73245          *  the exact semantics.
73246          *
73247          *  E5 Section 11.6.1.
73248          *
73249          *  Custom types also have special behavior implemented here.
73250          */
73251
73252         duk_double_union du;
73253
73254         DUK_ASSERT(thr != NULL);
73255         DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
73256         DUK_ASSERT(tv_y != NULL);  /* may be reg or const */
73257         DUK_ASSERT_DISABLE(idx_z >= 0);  /* unsigned */
73258         DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
73259
73260         /*
73261          *  Fast paths
73262          */
73263
73264 #if defined(DUK_USE_FASTINT)
73265         if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
73266                 duk_int64_t v1, v2, v3;
73267                 duk_int32_t v3_hi;
73268                 duk_tval *tv_z;
73269
73270                 /* Input values are signed 48-bit so we can detect overflow
73271                  * reliably from high bits or just a comparison.
73272                  */
73273
73274                 v1 = DUK_TVAL_GET_FASTINT(tv_x);
73275                 v2 = DUK_TVAL_GET_FASTINT(tv_y);
73276                 v3 = v1 + v2;
73277                 v3_hi = (duk_int32_t) (v3 >> 32);
73278                 if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) {
73279                         tv_z = thr->valstack_bottom + idx_z;
73280                         DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3);  /* side effects */
73281                         return;
73282                 } else {
73283                         /* overflow, fall through */
73284                         ;
73285                 }
73286         }
73287 #endif  /* DUK_USE_FASTINT */
73288
73289         if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
73290 #if !defined(DUK_USE_EXEC_PREFER_SIZE)
73291                 duk_tval *tv_z;
73292 #endif
73293
73294                 du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
73295 #if defined(DUK_USE_EXEC_PREFER_SIZE)
73296                 duk_push_number(thr, du.d);  /* will NaN normalize result */
73297                 duk_replace(thr, (duk_idx_t) idx_z);
73298 #else  /* DUK_USE_EXEC_PREFER_SIZE */
73299                 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
73300                 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
73301                 tv_z = thr->valstack_bottom + idx_z;
73302                 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d);  /* side effects */
73303 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
73304                 return;
73305         }
73306
73307         /*
73308          *  Slow path: potentially requires function calls for coercion
73309          */
73310
73311         duk_push_tval(thr, tv_x);
73312         duk_push_tval(thr, tv_y);
73313         duk_to_primitive(thr, -2, DUK_HINT_NONE);  /* side effects -> don't use tv_x, tv_y after */
73314         duk_to_primitive(thr, -1, DUK_HINT_NONE);
73315
73316         /* Since Duktape 2.x plain buffers are treated like ArrayBuffer. */
73317         if (duk_is_string(thr, -2) || duk_is_string(thr, -1)) {
73318                 /* Symbols shouldn't technically be handled here, but should
73319                  * go into the default ToNumber() coercion path instead and
73320                  * fail there with a TypeError.  However, there's a ToString()
73321                  * in duk_concat_2() which also fails with TypeError so no
73322                  * explicit check is needed.
73323                  */
73324                 duk_concat_2(thr);  /* [... s1 s2] -> [... s1+s2] */
73325         } else {
73326                 duk_double_t d1, d2;
73327
73328                 d1 = duk_to_number_m2(thr);
73329                 d2 = duk_to_number_m1(thr);
73330                 DUK_ASSERT(duk_is_number(thr, -2));
73331                 DUK_ASSERT(duk_is_number(thr, -1));
73332                 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
73333                 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
73334
73335                 du.d = d1 + d2;
73336                 duk_pop_2_unsafe(thr);
73337                 duk_push_number(thr, du.d);  /* will NaN normalize result */
73338         }
73339         duk_replace(thr, (duk_idx_t) idx_z);  /* side effects */
73340 }
73341
73342 DUK_LOCAL DUK__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) {
73343         /*
73344          *  Arithmetic operations other than '+' have number-only semantics
73345          *  and are implemented here.  The separate switch-case here means a
73346          *  "double dispatch" of the arithmetic opcode, but saves code space.
73347          *
73348          *  E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
73349          */
73350
73351         duk_double_t d1, d2;
73352         duk_double_union du;
73353         duk_small_uint_fast_t opcode_shifted;
73354 #if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE)
73355         duk_tval *tv_z;
73356 #endif
73357
73358         DUK_ASSERT(thr != NULL);
73359         DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
73360         DUK_ASSERT(tv_y != NULL);  /* may be reg or const */
73361         DUK_ASSERT_DISABLE(idx_z >= 0);  /* unsigned */
73362         DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
73363
73364         opcode_shifted = opcode >> 2;  /* Get base opcode without reg/const modifiers. */
73365
73366 #if defined(DUK_USE_FASTINT)
73367         if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
73368                 duk_int64_t v1, v2, v3;
73369                 duk_int32_t v3_hi;
73370
73371                 v1 = DUK_TVAL_GET_FASTINT(tv_x);
73372                 v2 = DUK_TVAL_GET_FASTINT(tv_y);
73373
73374                 switch (opcode_shifted) {
73375                 case DUK_OP_SUB >> 2: {
73376                         v3 = v1 - v2;
73377                         break;
73378                 }
73379                 case DUK_OP_MUL >> 2: {
73380                         /* Must ensure result is 64-bit (no overflow); a
73381                          * simple and sufficient fast path is to allow only
73382                          * 32-bit inputs.  Avoid zero inputs to avoid
73383                          * negative zero issues (-1 * 0 = -0, for instance).
73384                          */
73385                         if (v1 >= DUK_I64_CONSTANT(-0x80000000) && v1 <= DUK_I64_CONSTANT(0x7fffffff) && v1 != 0 &&
73386                             v2 >= DUK_I64_CONSTANT(-0x80000000) && v2 <= DUK_I64_CONSTANT(0x7fffffff) && v2 != 0) {
73387                                 v3 = v1 * v2;
73388                         } else {
73389                                 goto skip_fastint;
73390                         }
73391                         break;
73392                 }
73393                 case DUK_OP_DIV >> 2: {
73394                         /* Don't allow a zero divisor.  Fast path check by
73395                          * "verifying" with multiplication.  Also avoid zero
73396                          * dividend to avoid negative zero issues (0 / -1 = -0
73397                          * for instance).
73398                          */
73399                         if (v1 == 0 || v2 == 0) {
73400                                 goto skip_fastint;
73401                         }
73402                         v3 = v1 / v2;
73403                         if (v3 * v2 != v1) {
73404                                 goto skip_fastint;
73405                         }
73406                         break;
73407                 }
73408                 case DUK_OP_MOD >> 2: {
73409                         /* Don't allow a zero divisor.  Restrict both v1 and
73410                          * v2 to positive values to avoid compiler specific
73411                          * behavior.
73412                          */
73413                         if (v1 < 1 || v2 < 1) {
73414                                 goto skip_fastint;
73415                         }
73416                         v3 = v1 % v2;
73417                         DUK_ASSERT(v3 >= 0);
73418                         DUK_ASSERT(v3 < v2);
73419                         DUK_ASSERT(v1 - (v1 / v2) * v2 == v3);
73420                         break;
73421                 }
73422                 default: {
73423                         /* Possible with DUK_OP_EXP. */
73424                         goto skip_fastint;
73425                 }
73426                 }
73427
73428                 v3_hi = (duk_int32_t) (v3 >> 32);
73429                 if (DUK_LIKELY(v3_hi >= DUK_I64_CONSTANT(-0x8000) && v3_hi <= DUK_I64_CONSTANT(0x7fff))) {
73430                         tv_z = thr->valstack_bottom + idx_z;
73431                         DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3);  /* side effects */
73432                         return;
73433                 }
73434                 /* fall through if overflow etc */
73435         }
73436  skip_fastint:
73437 #endif  /* DUK_USE_FASTINT */
73438
73439         if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
73440                 /* fast path */
73441                 d1 = DUK_TVAL_GET_NUMBER(tv_x);
73442                 d2 = DUK_TVAL_GET_NUMBER(tv_y);
73443         } else {
73444                 duk_push_tval(thr, tv_x);
73445                 duk_push_tval(thr, tv_y);
73446                 d1 = duk_to_number_m2(thr);  /* side effects */
73447                 d2 = duk_to_number_m1(thr);
73448                 DUK_ASSERT(duk_is_number(thr, -2));
73449                 DUK_ASSERT(duk_is_number(thr, -1));
73450                 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
73451                 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
73452                 duk_pop_2_unsafe(thr);
73453         }
73454
73455         switch (opcode_shifted) {
73456         case DUK_OP_SUB >> 2: {
73457                 du.d = d1 - d2;
73458                 break;
73459         }
73460         case DUK_OP_MUL >> 2: {
73461                 du.d = d1 * d2;
73462                 break;
73463         }
73464         case DUK_OP_DIV >> 2: {
73465                 /* Division-by-zero is undefined behavior, so
73466                  * rely on a helper.
73467                  */
73468                 du.d = duk_double_div(d1, d2);
73469                 break;
73470         }
73471         case DUK_OP_MOD >> 2: {
73472                 du.d = duk__compute_mod(d1, d2);
73473                 break;
73474         }
73475 #if defined(DUK_USE_ES7_EXP_OPERATOR)
73476         case DUK_OP_EXP >> 2: {
73477                 du.d = duk__compute_exp(d1, d2);
73478                 break;
73479         }
73480 #endif
73481         default: {
73482                 DUK_UNREACHABLE();
73483                 du.d = DUK_DOUBLE_NAN;  /* should not happen */
73484                 break;
73485         }
73486         }
73487
73488 #if defined(DUK_USE_EXEC_PREFER_SIZE)
73489         duk_push_number(thr, du.d);  /* will NaN normalize result */
73490         duk_replace(thr, (duk_idx_t) idx_z);
73491 #else  /* DUK_USE_EXEC_PREFER_SIZE */
73492         /* important to use normalized NaN with 8-byte tagged types */
73493         DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
73494         DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
73495         tv_z = thr->valstack_bottom + idx_z;
73496         DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d);  /* side effects */
73497 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
73498 }
73499
73500 DUK_LOCAL DUK__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) {
73501         /*
73502          *  Binary bitwise operations use different coercions (ToInt32, ToUint32)
73503          *  depending on the operation.  We coerce the arguments first using
73504          *  ToInt32(), and then cast to an 32-bit value if necessary.  Note that
73505          *  such casts must be correct even if there is no native 32-bit type
73506          *  (e.g., duk_int32_t and duk_uint32_t are 64-bit).
73507          *
73508          *  E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
73509          */
73510
73511         duk_int32_t i1, i2, i3;
73512         duk_uint32_t u1, u2, u3;
73513 #if defined(DUK_USE_FASTINT)
73514         duk_int64_t fi3;
73515 #else
73516         duk_double_t d3;
73517 #endif
73518         duk_small_uint_fast_t opcode_shifted;
73519 #if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE)
73520         duk_tval *tv_z;
73521 #endif
73522
73523         DUK_ASSERT(thr != NULL);
73524         DUK_ASSERT(tv_x != NULL);  /* may be reg or const */
73525         DUK_ASSERT(tv_y != NULL);  /* may be reg or const */
73526         DUK_ASSERT_DISABLE(idx_z >= 0);  /* unsigned */
73527         DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(thr));
73528
73529         opcode_shifted = opcode >> 2;  /* Get base opcode without reg/const modifiers. */
73530
73531 #if defined(DUK_USE_FASTINT)
73532         if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
73533                 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
73534                 i2 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_y);
73535         }
73536         else
73537 #endif  /* DUK_USE_FASTINT */
73538         {
73539                 duk_push_tval(thr, tv_x);
73540                 duk_push_tval(thr, tv_y);
73541                 i1 = duk_to_int32(thr, -2);
73542                 i2 = duk_to_int32(thr, -1);
73543                 duk_pop_2_unsafe(thr);
73544         }
73545
73546         switch (opcode_shifted) {
73547         case DUK_OP_BAND >> 2: {
73548                 i3 = i1 & i2;
73549                 break;
73550         }
73551         case DUK_OP_BOR >> 2: {
73552                 i3 = i1 | i2;
73553                 break;
73554         }
73555         case DUK_OP_BXOR >> 2: {
73556                 i3 = i1 ^ i2;
73557                 break;
73558         }
73559         case DUK_OP_BASL >> 2: {
73560                 /* Signed shift, named "arithmetic" (asl) because the result
73561                  * is signed, e.g. 4294967295 << 1 -> -2.  Note that result
73562                  * must be masked.
73563                  */
73564
73565                 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
73566                 i3 = (duk_int32_t) (((duk_uint32_t) i1) << (u2 & 0x1fUL));  /* E5 Section 11.7.1, steps 7 and 8 */
73567                 i3 = i3 & ((duk_int32_t) 0xffffffffUL);                     /* Note: left shift, should mask */
73568                 break;
73569         }
73570         case DUK_OP_BASR >> 2: {
73571                 /* signed shift */
73572
73573                 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
73574                 i3 = i1 >> (u2 & 0x1fUL);                      /* E5 Section 11.7.2, steps 7 and 8 */
73575                 break;
73576         }
73577         case DUK_OP_BLSR >> 2: {
73578                 /* unsigned shift */
73579
73580                 u1 = ((duk_uint32_t) i1) & 0xffffffffUL;
73581                 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
73582
73583                 /* special result value handling */
73584                 u3 = u1 >> (u2 & 0x1fUL);     /* E5 Section 11.7.2, steps 7 and 8 */
73585 #if defined(DUK_USE_FASTINT)
73586                 fi3 = (duk_int64_t) u3;
73587                 goto fastint_result_set;
73588 #else
73589                 d3 = (duk_double_t) u3;
73590                 goto result_set;
73591 #endif
73592         }
73593         default: {
73594                 DUK_UNREACHABLE();
73595                 i3 = 0;  /* should not happen */
73596                 break;
73597         }
73598         }
73599
73600 #if defined(DUK_USE_FASTINT)
73601         /* Result is always fastint compatible. */
73602         /* XXX: Set 32-bit result (but must then handle signed and
73603          * unsigned results separately).
73604          */
73605         fi3 = (duk_int64_t) i3;
73606
73607  fastint_result_set:
73608         tv_z = thr->valstack_bottom + idx_z;
73609         DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3);  /* side effects */
73610 #else  /* DUK_USE_FASTINT */
73611         d3 = (duk_double_t) i3;
73612
73613  result_set:
73614         DUK_ASSERT(!DUK_ISNAN(d3));            /* 'd3' is never NaN, so no need to normalize */
73615         DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3);   /* always normalized */
73616
73617 #if defined(DUK_USE_EXEC_PREFER_SIZE)
73618         duk_push_number(thr, d3);  /* would NaN normalize result, but unnecessary */
73619         duk_replace(thr, (duk_idx_t) idx_z);
73620 #else  /* DUK_USE_EXEC_PREFER_SIZE */
73621         tv_z = thr->valstack_bottom + idx_z;
73622         DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3);  /* side effects */
73623 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
73624 #endif  /* DUK_USE_FASTINT */
73625 }
73626
73627 /* In-place unary operation. */
73628 DUK_LOCAL DUK__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) {
73629         /*
73630          *  Arithmetic operations other than '+' have number-only semantics
73631          *  and are implemented here.  The separate switch-case here means a
73632          *  "double dispatch" of the arithmetic opcode, but saves code space.
73633          *
73634          *  E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
73635          */
73636
73637         duk_tval *tv;
73638         duk_double_t d1;
73639         duk_double_union du;
73640
73641         DUK_ASSERT(thr != NULL);
73642         DUK_ASSERT(opcode == DUK_OP_UNM || opcode == DUK_OP_UNP);
73643         DUK_ASSERT_DISABLE(idx_src >= 0);
73644         DUK_ASSERT_DISABLE(idx_dst >= 0);
73645
73646         tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
73647
73648 #if defined(DUK_USE_FASTINT)
73649         if (DUK_TVAL_IS_FASTINT(tv)) {
73650                 duk_int64_t v1, v2;
73651
73652                 v1 = DUK_TVAL_GET_FASTINT(tv);
73653                 if (opcode == DUK_OP_UNM) {
73654                         /* The smallest fastint is no longer 48-bit when
73655                          * negated.  Positive zero becames negative zero
73656                          * (cannot be represented) when negated.
73657                          */
73658                         if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) {
73659                                 v2 = -v1;
73660                                 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
73661                                 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
73662                                 return;
73663                         }
73664                 } else {
73665                         /* ToNumber() for a fastint is a no-op. */
73666                         DUK_ASSERT(opcode == DUK_OP_UNP);
73667                         v2 = v1;
73668                         tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
73669                         DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
73670                         return;
73671                 }
73672                 /* fall through if overflow etc */
73673         }
73674 #endif  /* DUK_USE_FASTINT */
73675
73676         if (DUK_TVAL_IS_NUMBER(tv)) {
73677                 d1 = DUK_TVAL_GET_NUMBER(tv);
73678         } else {
73679                 d1 = duk_to_number_tval(thr, tv);  /* side effects */
73680         }
73681
73682         if (opcode == DUK_OP_UNP) {
73683                 /* ToNumber() for a double is a no-op, but unary plus is
73684                  * used to force a fastint check so do that here.
73685                  */
73686                 du.d = d1;
73687                 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
73688 #if defined(DUK_USE_FASTINT)
73689                 tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
73690                 DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d);  /* always 'fast', i.e. inlined */
73691                 return;
73692 #endif
73693         } else {
73694                 DUK_ASSERT(opcode == DUK_OP_UNM);
73695                 du.d = -d1;
73696                 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);  /* mandatory if du.d is a NaN */
73697                 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
73698         }
73699
73700         /* XXX: size optimize: push+replace? */
73701         tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
73702         DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, du.d);
73703 }
73704
73705 DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) {
73706         /*
73707          *  E5 Section 11.4.8
73708          */
73709
73710         duk_tval *tv;
73711         duk_int32_t i1, i2;
73712
73713         DUK_ASSERT(thr != NULL);
73714         DUK_ASSERT_DISABLE(idx_src >= 0);
73715         DUK_ASSERT_DISABLE(idx_dst >= 0);
73716         DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr));
73717         DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr));
73718
73719         tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
73720
73721 #if defined(DUK_USE_FASTINT)
73722         if (DUK_TVAL_IS_FASTINT(tv)) {
73723                 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv);
73724         }
73725         else
73726 #endif  /* DUK_USE_FASTINT */
73727         {
73728                 duk_push_tval(thr, tv);
73729                 i1 = duk_to_int32(thr, -1);  /* side effects */
73730                 duk_pop_unsafe(thr);
73731         }
73732
73733         /* Result is always fastint compatible. */
73734         i2 = ~i1;
73735         tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
73736         DUK_TVAL_SET_I32_UPDREF(thr, tv, i2);  /* side effects */
73737 }
73738
73739 DUK_LOCAL DUK__INLINE_PERF void duk__vm_logical_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) {
73740         /*
73741          *  E5 Section 11.4.9
73742          */
73743
73744         duk_tval *tv;
73745         duk_bool_t res;
73746
73747         DUK_ASSERT(thr != NULL);
73748         DUK_ASSERT_DISABLE(idx_src >= 0);
73749         DUK_ASSERT_DISABLE(idx_dst >= 0);
73750         DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(thr));
73751         DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(thr));
73752
73753         /* ToBoolean() does not require any operations with side effects so
73754          * we can do it efficiently.  For footprint it would be better to use
73755          * duk_js_toboolean() and then push+replace to the result slot.
73756          */
73757         tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_src);
73758         res = duk_js_toboolean(tv);  /* does not modify 'tv' */
73759         DUK_ASSERT(res == 0 || res == 1);
73760         res ^= 1;
73761         tv = DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst);
73762         /* XXX: size optimize: push+replace? */
73763         DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, res);  /* side effects */
73764 }
73765
73766 /* XXX: size optimized variant */
73767 DUK_LOCAL DUK__INLINE_PERF void duk__prepost_incdec_reg_helper(duk_hthread *thr, duk_tval *tv_dst, duk_tval *tv_src, duk_small_uint_t op) {
73768         duk_double_t x, y, z;
73769
73770         /* Two lowest bits of opcode are used to distinguish
73771          * variants.  Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
73772          */
73773         DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00);
73774         DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01);
73775         DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02);
73776         DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03);
73777
73778 #if defined(DUK_USE_FASTINT)
73779         if (DUK_TVAL_IS_FASTINT(tv_src)) {
73780                 duk_int64_t x_fi, y_fi, z_fi;
73781                 x_fi = DUK_TVAL_GET_FASTINT(tv_src);
73782                 if (op & 0x01) {
73783                         if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MIN)) {
73784                                 goto skip_fastint;
73785                         }
73786                         y_fi = x_fi - 1;
73787                 } else {
73788                         if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MAX)) {
73789                                 goto skip_fastint;
73790                         }
73791                         y_fi = x_fi + 1;
73792                 }
73793
73794                 DUK_TVAL_SET_FASTINT(tv_src, y_fi);  /* no need for refcount update */
73795
73796                 z_fi = (op & 0x02) ? x_fi : y_fi;
73797                 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_dst, z_fi);  /* side effects */
73798                 return;
73799         }
73800  skip_fastint:
73801 #endif
73802         if (DUK_TVAL_IS_NUMBER(tv_src)) {
73803                 /* Fast path for the case where the register
73804                  * is a number (e.g. loop counter).
73805                  */
73806
73807                 x = DUK_TVAL_GET_NUMBER(tv_src);
73808                 if (op & 0x01) {
73809                         y = x - 1.0;
73810                 } else {
73811                         y = x + 1.0;
73812                 }
73813
73814                 DUK_TVAL_SET_NUMBER(tv_src, y);  /* no need for refcount update */
73815         } else {
73816                 /* Preserve duk_tval pointer(s) across a potential valstack
73817                  * resize by converting them into offsets temporarily.
73818                  */
73819                 duk_idx_t bc;
73820                 duk_size_t off_dst;
73821
73822                 off_dst = (duk_size_t) ((duk_uint8_t *) tv_dst - (duk_uint8_t *) thr->valstack_bottom);
73823                 bc = (duk_idx_t) (tv_src - thr->valstack_bottom);  /* XXX: pass index explicitly? */
73824                 tv_src = NULL;  /* no longer referenced */
73825
73826                 x = duk_to_number(thr, bc);
73827                 if (op & 0x01) {
73828                         y = x - 1.0;
73829                 } else {
73830                         y = x + 1.0;
73831                 }
73832
73833                 duk_push_number(thr, y);
73834                 duk_replace(thr, bc);
73835
73836                 tv_dst = (duk_tval *) (void *) (((duk_uint8_t *) thr->valstack_bottom) + off_dst);
73837         }
73838
73839         z = (op & 0x02) ? x : y;
73840         DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z);  /* side effects */
73841 }
73842
73843 DUK_LOCAL DUK__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) {
73844         duk_activation *act;
73845         duk_double_t x, y;
73846         duk_hstring *name;
73847
73848         /* XXX: The pre/post inc/dec for an identifier lookup is
73849          * missing the important fast path where the identifier
73850          * has a storage location e.g. in a scope object so that
73851          * it can be updated in-place.  In particular, the case
73852          * where the identifier has a storage location AND the
73853          * previous value is a number should be optimized because
73854          * it's side effect free.
73855          */
73856
73857         /* Two lowest bits of opcode are used to distinguish
73858          * variants.  Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
73859          */
73860         DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00);
73861         DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01);
73862         DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02);
73863         DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03);
73864
73865         DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id));
73866         name = DUK_TVAL_GET_STRING(tv_id);
73867         DUK_ASSERT(name != NULL);
73868         act = thr->callstack_curr;
73869         (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/);  /* -> [ ... val this ] */
73870
73871         /* XXX: Fastint fast path would be useful here.  Also fastints
73872          * now lose their fastint status in current handling which is
73873          * not intuitive.
73874          */
73875
73876         x = duk_to_number_m2(thr);
73877         if (op & 0x01) {
73878                 y = x - 1.0;
73879         } else {
73880                 y = x + 1.0;
73881         }
73882
73883         /* [... x this] */
73884
73885         if (op & 0x02) {
73886                 duk_push_number(thr, y);  /* -> [ ... x this y ] */
73887                 DUK_ASSERT(act == thr->callstack_curr);
73888                 duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict);
73889                 duk_pop_2_unsafe(thr);  /* -> [ ... x ] */
73890         } else {
73891                 duk_pop_2_unsafe(thr);  /* -> [ ... ] */
73892                 duk_push_number(thr, y);  /* -> [ ... y ] */
73893                 DUK_ASSERT(act == thr->callstack_curr);
73894                 duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(thr, -1), is_strict);
73895         }
73896
73897 #if defined(DUK_USE_EXEC_PREFER_SIZE)
73898         duk_replace(thr, (duk_idx_t) idx_dst);
73899 #else  /* DUK_USE_EXEC_PREFER_SIZE */
73900         DUK__REPLACE_TO_TVPTR(thr, DUK_GET_TVAL_POSIDX(thr, (duk_idx_t) idx_dst));
73901 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
73902 }
73903
73904 /*
73905  *  Longjmp and other control flow transfer for the bytecode executor.
73906  *
73907  *  The longjmp handler can handle all longjmp types: error, yield, and
73908  *  resume (pseudotypes are never actually thrown).
73909  *
73910  *  Error policy for longjmp: should not ordinarily throw errors; if errors
73911  *  occur (e.g. due to out-of-memory) they bubble outwards rather than being
73912  *  handled recursively.
73913  */
73914
73915 #define DUK__LONGJMP_RESTART   0  /* state updated, restart bytecode execution */
73916 #define DUK__LONGJMP_RETHROW   1  /* exit bytecode executor by rethrowing an error to caller */
73917
73918 #define DUK__RETHAND_RESTART   0  /* state updated, restart bytecode execution */
73919 #define DUK__RETHAND_FINISHED  1  /* exit bytecode execution with return value */
73920
73921 /* XXX: optimize reconfig valstack operations so that resize, clamp, and setting
73922  * top are combined into one pass.
73923  */
73924
73925 /* Reconfigure value stack for return to an ECMAScript function at
73926  * callstack top (caller unwinds).
73927  */
73928 DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr) {
73929         duk_activation *act;
73930         duk_hcompfunc *h_func;
73931         duk_idx_t clamp_top;
73932
73933         DUK_ASSERT(thr != NULL);
73934         act = thr->callstack_curr;
73935         DUK_ASSERT(act != NULL);
73936         DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
73937         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
73938
73939         /* Clamp so that values at 'clamp_top' and above are wiped and won't
73940          * retain reachable garbage.  Then extend to 'nregs' because we're
73941          * returning to an ECMAScript function.
73942          */
73943
73944         h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
73945
73946         thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
73947         DUK_ASSERT(act->retval_byteoff >= act->bottom_byteoff);
73948         clamp_top = (duk_idx_t) ((act->retval_byteoff - act->bottom_byteoff + sizeof(duk_tval)) / sizeof(duk_tval));  /* +1 = one retval */
73949         duk_set_top_and_wipe(thr, h_func->nregs, clamp_top);
73950
73951         DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff);
73952         thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff);
73953
73954         /* XXX: a best effort shrink check would be OK here */
73955 }
73956
73957 /* Reconfigure value stack for an ECMAScript catcher.  Use topmost catcher
73958  * in 'act'.
73959  */
73960 DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_activation *act) {
73961         duk_catcher *cat;
73962         duk_hcompfunc *h_func;
73963         duk_size_t idx_bottom;
73964         duk_idx_t clamp_top;
73965
73966         DUK_ASSERT(thr != NULL);
73967         DUK_ASSERT(act != NULL);
73968         DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
73969         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
73970         cat = act->cat;
73971         DUK_ASSERT(cat != NULL);
73972
73973         h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
73974
73975         thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
73976         idx_bottom = (duk_size_t) (thr->valstack_bottom - thr->valstack);
73977         DUK_ASSERT(cat->idx_base >= idx_bottom);
73978         clamp_top = (duk_idx_t) (cat->idx_base - idx_bottom + 2);  /* +2 = catcher value, catcher lj_type */
73979         duk_set_top_and_wipe(thr, h_func->nregs, clamp_top);
73980
73981         DUK_ASSERT((duk_uint8_t *) thr->valstack_end >= (duk_uint8_t *) thr->valstack + act->reserve_byteoff);
73982         thr->valstack_end = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->reserve_byteoff);
73983
73984         /* XXX: a best effort shrink check would be OK here */
73985 }
73986
73987 /* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type.
73988  * No side effects.
73989  */
73990 DUK_LOCAL void duk__set_catcher_regs_norz(duk_hthread *thr, duk_catcher *cat, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
73991         duk_tval *tv1;
73992
73993         DUK_ASSERT(thr != NULL);
73994         DUK_ASSERT(tv_val_unstable != NULL);
73995
73996         tv1 = thr->valstack + cat->idx_base;
73997         DUK_ASSERT(tv1 < thr->valstack_top);
73998         DUK_TVAL_SET_TVAL_UPDREF_NORZ(thr, tv1, tv_val_unstable);
73999
74000         tv1++;
74001         DUK_ASSERT(tv1 == thr->valstack + cat->idx_base + 1);
74002         DUK_ASSERT(tv1 < thr->valstack_top);
74003         DUK_TVAL_SET_U32_UPDREF_NORZ(thr, tv1, (duk_uint32_t) lj_type);
74004 }
74005
74006 DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
74007         duk_activation *act;
74008         duk_catcher *cat;
74009
74010         DUK_ASSERT(thr != NULL);
74011         DUK_ASSERT(tv_val_unstable != NULL);
74012
74013         act = thr->callstack_curr;
74014         DUK_ASSERT(act != NULL);
74015         DUK_ASSERT(act->cat != NULL);
74016         DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
74017
74018         duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type);
74019
74020         DUK_ASSERT(thr->callstack_top >= 1);
74021         DUK_ASSERT(thr->callstack_curr != NULL);
74022         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
74023         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
74024
74025         DUK_ASSERT(thr->callstack_top >= 1);
74026         DUK_ASSERT(act == thr->callstack_curr);
74027         DUK_ASSERT(act != NULL);
74028         duk__reconfig_valstack_ecma_catcher(thr, act);
74029
74030         DUK_ASSERT(thr->callstack_top >= 1);
74031         DUK_ASSERT(act == thr->callstack_curr);
74032         DUK_ASSERT(act != NULL);
74033         cat = act->cat;
74034         DUK_ASSERT(cat != NULL);
74035
74036         act->curr_pc = cat->pc_base + 0;  /* +0 = catch */
74037
74038         /*
74039          *  If entering a 'catch' block which requires an automatic
74040          *  catch variable binding, create the lexical environment.
74041          *
74042          *  The binding is mutable (= writable) but not deletable.
74043          *  Step 4 for the catch production in E5 Section 12.14;
74044          *  no value is given for CreateMutableBinding 'D' argument,
74045          *  which implies the binding is not deletable.
74046          */
74047
74048         if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat)) {
74049                 duk_hdecenv *new_env;
74050
74051                 DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding"));
74052
74053                 DUK_ASSERT(thr->callstack_top >= 1);
74054                 DUK_ASSERT(act == thr->callstack_curr);
74055                 DUK_ASSERT(act != NULL);
74056
74057                 if (act->lex_env == NULL) {
74058                         DUK_ASSERT(act->var_env == NULL);
74059                         DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
74060
74061                         duk_js_init_activation_environment_records_delayed(thr, act);
74062                         DUK_ASSERT(act == thr->callstack_curr);
74063                         DUK_ASSERT(act != NULL);
74064                 }
74065                 DUK_ASSERT(act->lex_env != NULL);
74066                 DUK_ASSERT(act->var_env != NULL);
74067                 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
74068
74069                 /* XXX: If an out-of-memory happens here, longjmp state asserts
74070                  * will be triggered at present and a try-catch fails to catch.
74071                  * That's not sandboxing fatal (C API protected calls are what
74072                  * matters), and script catch code can immediately throw anyway
74073                  * for almost any operation.
74074                  */
74075                 new_env = duk_hdecenv_alloc(thr,
74076                                             DUK_HOBJECT_FLAG_EXTENSIBLE |
74077                                             DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
74078                 DUK_ASSERT(new_env != NULL);
74079                 duk_push_hobject(thr, (duk_hobject *) new_env);
74080                 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
74081                 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
74082
74083                 /* Note: currently the catch binding is handled without a register
74084                  * binding because we don't support dynamic register bindings (they
74085                  * must be fixed for an entire function).  So, there is no need to
74086                  * record regbases etc.
74087                  */
74088
74089                 /* XXX: duk_xdef_prop() may cause an out-of-memory, see above. */
74090                 DUK_ASSERT(cat->h_varname != NULL);
74091                 duk_push_hstring(thr, cat->h_varname);
74092                 duk_push_tval(thr, thr->valstack + cat->idx_base);
74093                 duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_W);  /* writable, not configurable */
74094
74095                 DUK_ASSERT(act == thr->callstack_curr);
74096                 DUK_ASSERT(act != NULL);
74097                 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, act->lex_env);
74098                 act->lex_env = (duk_hobject *) new_env;
74099                 DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);  /* reachable through activation */
74100                 /* Net refcount change to act->lex_env is 0: incref for new_env's
74101                  * prototype, decref for act->lex_env overwrite.
74102                  */
74103
74104                 DUK_CAT_SET_LEXENV_ACTIVE(cat);
74105
74106                 duk_pop_unsafe(thr);
74107
74108                 DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env));
74109         }
74110
74111         DUK_CAT_CLEAR_CATCH_ENABLED(cat);
74112 }
74113
74114 DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
74115         duk_activation *act;
74116         duk_catcher *cat;
74117
74118         DUK_ASSERT(thr != NULL);
74119         DUK_ASSERT(tv_val_unstable != NULL);
74120
74121         act = thr->callstack_curr;
74122         DUK_ASSERT(act != NULL);
74123         DUK_ASSERT(act->cat != NULL);
74124         DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
74125
74126         duk__set_catcher_regs_norz(thr, act->cat, tv_val_unstable, lj_type);
74127
74128         DUK_ASSERT(thr->callstack_top >= 1);
74129         DUK_ASSERT(thr->callstack_curr != NULL);
74130         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
74131         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
74132
74133         DUK_ASSERT(thr->callstack_top >= 1);
74134         DUK_ASSERT(act == thr->callstack_curr);
74135         DUK_ASSERT(act != NULL);
74136         duk__reconfig_valstack_ecma_catcher(thr, act);
74137
74138         DUK_ASSERT(thr->callstack_top >= 1);
74139         DUK_ASSERT(act == thr->callstack_curr);
74140         DUK_ASSERT(act != NULL);
74141         cat = act->cat;
74142         DUK_ASSERT(cat != NULL);
74143
74144         act->curr_pc = cat->pc_base + 1;  /* +1 = finally */
74145
74146         DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
74147 }
74148
74149 DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_small_uint_t lj_type) {
74150         duk_activation *act;
74151         duk_catcher *cat;
74152
74153         DUK_ASSERT(thr != NULL);
74154
74155         DUK_ASSERT(thr->callstack_top >= 1);
74156         act = thr->callstack_curr;
74157         DUK_ASSERT(act != NULL);
74158         DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
74159         DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
74160
74161         /* +0 = break, +1 = continue */
74162         cat = act->cat;
74163         DUK_ASSERT(cat != NULL);
74164         DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
74165
74166         act->curr_pc = cat->pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
74167
74168         /* valstack should not need changes */
74169 #if defined(DUK_USE_ASSERTIONS)
74170         DUK_ASSERT(thr->callstack_top >= 1);
74171         DUK_ASSERT(act == thr->callstack_curr);
74172         DUK_ASSERT(act != NULL);
74173         DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) ==
74174                    (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs);
74175 #endif
74176 }
74177
74178 /* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and
74179  * when a RETURN opcode terminates a thread and yields to the resumer.
74180  * Caller unwinds so that top of callstack is the activation we return to.
74181  */
74182 #if defined(DUK_USE_COROUTINE_SUPPORT)
74183 DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_tval *tv_val_unstable) {
74184         duk_activation *act_resumer;
74185         duk_tval *tv1;
74186
74187         DUK_ASSERT(thr != NULL);
74188         DUK_ASSERT(resumer != NULL);
74189         DUK_ASSERT(tv_val_unstable != NULL);
74190         act_resumer = resumer->callstack_curr;
74191         DUK_ASSERT(act_resumer != NULL);
74192         DUK_ASSERT(DUK_ACT_GET_FUNC(act_resumer) != NULL);
74193         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act_resumer)));  /* resume caller must be an ECMAScript func */
74194
74195         tv1 = (duk_tval *) (void *) ((duk_uint8_t *) resumer->valstack + act_resumer->retval_byteoff);  /* return value from Duktape.Thread.resume() */
74196         DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable);  /* side effects */  /* XXX: avoid side effects */
74197
74198         duk__reconfig_valstack_ecma_return(resumer);
74199
74200         /* caller must change active thread, and set thr->resumer to NULL */
74201 }
74202 #endif  /* DUK_USE_COROUTINE_SUPPORT */
74203
74204 DUK_LOCAL duk_small_uint_t duk__handle_longjmp(duk_hthread *thr, duk_activation *entry_act) {
74205         duk_small_uint_t retval = DUK__LONGJMP_RESTART;
74206
74207         DUK_ASSERT(thr != NULL);
74208         DUK_ASSERT(entry_act != NULL);
74209
74210         /* 'thr' is the current thread, as no-one resumes except us and we
74211          * switch 'thr' in that case.
74212          */
74213         DUK_ASSERT(thr == thr->heap->curr_thread);
74214
74215         /*
74216          *  (Re)try handling the longjmp.
74217          *
74218          *  A longjmp handler may convert the longjmp to a different type and
74219          *  "virtually" rethrow by goto'ing to 'check_longjmp'.  Before the goto,
74220          *  the following must be updated:
74221          *    - the heap 'lj' state
74222          *    - 'thr' must reflect the "throwing" thread
74223          */
74224
74225  check_longjmp:
74226
74227         DUK_DD(DUK_DDPRINT("handling longjmp: type=%ld, value1=%!T, value2=%!T, iserror=%ld",
74228                            (long) thr->heap->lj.type,
74229                            (duk_tval *) &thr->heap->lj.value1,
74230                            (duk_tval *) &thr->heap->lj.value2,
74231                            (long) thr->heap->lj.iserror));
74232
74233         switch (thr->heap->lj.type) {
74234
74235 #if defined(DUK_USE_COROUTINE_SUPPORT)
74236         case DUK_LJ_TYPE_RESUME: {
74237                 /*
74238                  *  Note: lj.value1 is 'value', lj.value2 is 'resumee'.
74239                  *  This differs from YIELD.
74240                  */
74241
74242                 duk_tval *tv;
74243                 duk_tval *tv2;
74244                 duk_hthread *resumee;
74245
74246                 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
74247
74248                 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);                                                         /* unchanged by Duktape.Thread.resume() */
74249                 DUK_ASSERT(thr->callstack_top >= 2);                                                                         /* ECMAScript activation + Duktape.Thread.resume() activation */
74250                 DUK_ASSERT(thr->callstack_curr != NULL);
74251                 DUK_ASSERT(thr->callstack_curr->parent != NULL);
74252                 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL &&
74253                            DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) &&
74254                            ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_resume);
74255
74256                 tv = &thr->heap->lj.value2;  /* resumee */
74257                 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
74258                 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
74259                 DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
74260                 resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
74261
74262                 DUK_ASSERT(resumee != NULL);
74263                 DUK_ASSERT(resumee->resumer == NULL);
74264                 DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE ||
74265                            resumee->state == DUK_HTHREAD_STATE_YIELDED);                                                     /* checked by Duktape.Thread.resume() */
74266                 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
74267                            resumee->callstack_top >= 2);                                                                     /* YIELDED: ECMAScript activation + Duktape.Thread.yield() activation */
74268                 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
74269                            (DUK_ACT_GET_FUNC(resumee->callstack_curr) != NULL &&
74270                             DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack_curr)) &&
74271                             ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack_curr))->func == duk_bi_thread_yield));
74272                 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
74273                            resumee->callstack_top == 0);                                                                     /* INACTIVE: no activation, single function value on valstack */
74274
74275                 if (thr->heap->lj.iserror) {
74276                         /*
74277                          *  Throw the error in the resumed thread's context; the
74278                          *  error value is pushed onto the resumee valstack.
74279                          *
74280                          *  Note: the callstack of the target may empty in this case
74281                          *  too (i.e. the target thread has never been resumed).  The
74282                          *  value stack will contain the initial function in that case,
74283                          *  which we simply ignore.
74284                          */
74285
74286                         DUK_ASSERT(resumee->resumer == NULL);
74287                         resumee->resumer = thr;
74288                         DUK_HTHREAD_INCREF(thr, thr);
74289                         resumee->state = DUK_HTHREAD_STATE_RUNNING;
74290                         thr->state = DUK_HTHREAD_STATE_RESUMED;
74291                         DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
74292                         thr = resumee;
74293
74294                         thr->heap->lj.type = DUK_LJ_TYPE_THROW;
74295
74296                         /* thr->heap->lj.value1 is already the value to throw */
74297                         /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */
74298
74299                         DUK_ASSERT(thr->heap->lj.iserror);  /* already set */
74300
74301                         DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate"));
74302                         goto check_longjmp;
74303                 } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
74304                         /* Unwind previous Duktape.Thread.yield() call.  The
74305                          * activation remaining must always be an ECMAScript
74306                          * call now (yield() accepts calls from ECMAScript
74307                          * only).
74308                          */
74309                         duk_activation *act_resumee;
74310
74311                         DUK_ASSERT(resumee->callstack_top >= 2);
74312                         act_resumee = resumee->callstack_curr;  /* Duktape.Thread.yield() */
74313                         DUK_ASSERT(act_resumee != NULL);
74314                         act_resumee = act_resumee->parent;      /* ECMAScript call site for yield() */
74315                         DUK_ASSERT(act_resumee != NULL);
74316
74317                         tv = (duk_tval *) (void *) ((duk_uint8_t *) resumee->valstack + act_resumee->retval_byteoff);  /* return value from Duktape.Thread.yield() */
74318                         DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
74319                         tv2 = &thr->heap->lj.value1;
74320                         DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2);  /* side effects */  /* XXX: avoid side effects */
74321
74322                         duk_hthread_activation_unwind_norz(resumee);  /* unwind to 'yield' caller */
74323                         /* no need to unwind catch stack */
74324
74325                         duk__reconfig_valstack_ecma_return(resumee);
74326
74327                         DUK_ASSERT(resumee->resumer == NULL);
74328                         resumee->resumer = thr;
74329                         DUK_HTHREAD_INCREF(thr, thr);
74330                         resumee->state = DUK_HTHREAD_STATE_RUNNING;
74331                         thr->state = DUK_HTHREAD_STATE_RESUMED;
74332                         DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
74333 #if 0
74334                         thr = resumee;  /* not needed, as we exit right away */
74335 #endif
74336                         DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
74337                         retval = DUK__LONGJMP_RESTART;
74338                         goto wipe_and_return;
74339                 } else {
74340                         /* Initial resume call. */
74341                         duk_small_uint_t call_flags;
74342                         duk_int_t setup_rc;
74343
74344                         /* resumee: [... initial_func]  (currently actually: [initial_func]) */
74345
74346                         duk_push_undefined(resumee);
74347                         tv = &thr->heap->lj.value1;
74348                         duk_push_tval(resumee, tv);
74349
74350                         /* resumee: [... initial_func undefined(= this) resume_value ] */
74351
74352                         call_flags = DUK_CALL_FLAG_ALLOW_ECMATOECMA;  /* not tailcall, ecma-to-ecma (assumed to succeed) */
74353
74354                         setup_rc = duk_handle_call_unprotected_nargs(resumee, 1 /*nargs*/, call_flags);
74355                         if (setup_rc == 0) {
74356                                 /* This shouldn't happen; Duktape.Thread.resume()
74357                                  * should make sure of that.  If it does happen
74358                                  * this internal error will propagate out of the
74359                                  * executor which can be quite misleading.
74360                                  */
74361                                 DUK_ERROR_INTERNAL(thr);
74362                                 DUK_WO_NORETURN(return 0;);
74363                         }
74364
74365                         DUK_ASSERT(resumee->resumer == NULL);
74366                         resumee->resumer = thr;
74367                         DUK_HTHREAD_INCREF(thr, thr);
74368                         resumee->state = DUK_HTHREAD_STATE_RUNNING;
74369                         thr->state = DUK_HTHREAD_STATE_RESUMED;
74370                         DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
74371 #if 0
74372                         thr = resumee;  /* not needed, as we exit right away */
74373 #endif
74374                         DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
74375                         retval = DUK__LONGJMP_RESTART;
74376                         goto wipe_and_return;
74377                 }
74378                 DUK_UNREACHABLE();
74379                 break;  /* never here */
74380         }
74381
74382         case DUK_LJ_TYPE_YIELD: {
74383                 /*
74384                  *  Currently only allowed only if yielding thread has only
74385                  *  ECMAScript activations (except for the Duktape.Thread.yield()
74386                  *  call at the callstack top) and none of them constructor
74387                  *  calls.
74388                  *
74389                  *  This excludes the 'entry' thread which will always have
74390                  *  a preventcount > 0.
74391                  */
74392
74393                 duk_hthread *resumer;
74394
74395                 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
74396
74397 #if 0  /* entry_thread not available for assert */
74398                 DUK_ASSERT(thr != entry_thread);                                                                             /* Duktape.Thread.yield() should prevent */
74399 #endif
74400                 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);                                                         /* unchanged from Duktape.Thread.yield() */
74401                 DUK_ASSERT(thr->callstack_top >= 2);                                                                         /* ECMAScript activation + Duktape.Thread.yield() activation */
74402                 DUK_ASSERT(thr->callstack_curr != NULL);
74403                 DUK_ASSERT(thr->callstack_curr->parent != NULL);
74404                 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL &&
74405                            DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)) &&
74406                            ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack_curr))->func == duk_bi_thread_yield);
74407                 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr->parent) != NULL &&
74408                            DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent)));                              /* an ECMAScript function */
74409
74410                 resumer = thr->resumer;
74411
74412                 DUK_ASSERT(resumer != NULL);
74413                 DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED);                                                     /* written by a previous RESUME handling */
74414                 DUK_ASSERT(resumer->callstack_top >= 2);                                                                     /* ECMAScript activation + Duktape.Thread.resume() activation */
74415                 DUK_ASSERT(resumer->callstack_curr != NULL);
74416                 DUK_ASSERT(resumer->callstack_curr->parent != NULL);
74417                 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr) != NULL &&
74418                            DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr)) &&
74419                            ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack_curr))->func == duk_bi_thread_resume);
74420                 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent) != NULL &&
74421                            DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack_curr->parent)));                            /* an ECMAScript function */
74422
74423                 if (thr->heap->lj.iserror) {
74424                         thr->state = DUK_HTHREAD_STATE_YIELDED;
74425                         thr->resumer = NULL;
74426                         DUK_HTHREAD_DECREF_NORZ(thr, resumer);
74427                         resumer->state = DUK_HTHREAD_STATE_RUNNING;
74428                         DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
74429                         thr = resumer;
74430
74431                         thr->heap->lj.type = DUK_LJ_TYPE_THROW;
74432                         /* lj.value1 is already set */
74433                         DUK_ASSERT(thr->heap->lj.iserror);  /* already set */
74434
74435                         DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
74436                         goto check_longjmp;
74437                 } else {
74438                         duk_hthread_activation_unwind_norz(resumer);
74439                         duk__handle_yield(thr, resumer, &thr->heap->lj.value1);
74440
74441                         thr->state = DUK_HTHREAD_STATE_YIELDED;
74442                         thr->resumer = NULL;
74443                         DUK_HTHREAD_DECREF_NORZ(thr, resumer);
74444                         resumer->state = DUK_HTHREAD_STATE_RUNNING;
74445                         DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
74446 #if 0
74447                         thr = resumer;  /* not needed, as we exit right away */
74448 #endif
74449
74450                         DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer"));
74451                         retval = DUK__LONGJMP_RESTART;
74452                         goto wipe_and_return;
74453                 }
74454                 DUK_UNREACHABLE();
74455                 break;  /* never here */
74456         }
74457 #endif  /* DUK_USE_COROUTINE_SUPPORT */
74458
74459         case DUK_LJ_TYPE_THROW: {
74460                 /*
74461                  *  Three possible outcomes:
74462                  *    * A try or finally catcher is found => resume there.
74463                  *      (or)
74464                  *    * The error propagates to the bytecode executor entry
74465                  *      level (and we're in the entry thread) => rethrow
74466                  *      with a new longjmp(), after restoring the previous
74467                  *      catchpoint.
74468                  *    * The error is not caught in the current thread, so
74469                  *      the thread finishes with an error.  This works like
74470                  *      a yielded error, except that the thread is finished
74471                  *      and can no longer be resumed.  (There is always a
74472                  *      resumer in this case.)
74473                  *
74474                  *  Note: until we hit the entry level, there can only be
74475                  *  ECMAScript activations.
74476                  */
74477
74478                 duk_activation *act;
74479                 duk_catcher *cat;
74480                 duk_hthread *resumer;
74481
74482                 for (;;) {
74483                         act = thr->callstack_curr;
74484                         if (act == NULL) {
74485                                 break;
74486                         }
74487
74488                         for (;;) {
74489                                 cat = act->cat;
74490                                 if (cat == NULL) {
74491                                         break;
74492                                 }
74493
74494                                 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
74495                                         DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
74496
74497                                         duk__handle_catch(thr,
74498                                                           &thr->heap->lj.value1,
74499                                                           DUK_LJ_TYPE_THROW);
74500
74501                                         DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
74502                                         retval = DUK__LONGJMP_RESTART;
74503                                         goto wipe_and_return;
74504                                 }
74505
74506                                 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
74507                                         DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
74508                                         DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
74509
74510                                         duk__handle_finally(thr,
74511                                                             &thr->heap->lj.value1,
74512                                                             DUK_LJ_TYPE_THROW);
74513
74514                                         DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
74515                                         retval = DUK__LONGJMP_RESTART;
74516                                         goto wipe_and_return;
74517                                 }
74518
74519                                 duk_hthread_catcher_unwind_norz(thr, act);
74520                         }
74521
74522                         if (act == entry_act) {
74523                                 /* Not caught by anything before entry level; rethrow and let the
74524                                  * final catcher finish unwinding (esp. value stack).
74525                                  */
74526                                 DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
74527                                 retval = DUK__LONGJMP_RETHROW;
74528                                 goto just_return;
74529                         }
74530
74531                         duk_hthread_activation_unwind_norz(thr);
74532                 }
74533
74534                 DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp"));
74535
74536                 /* Not caught by current thread, thread terminates (yield error to resumer);
74537                  * note that this may cause a cascade if the resumer terminates with an uncaught
74538                  * exception etc (this is OK, but needs careful testing).
74539                  */
74540
74541                 DUK_ASSERT(thr->resumer != NULL);
74542                 DUK_ASSERT(thr->resumer->callstack_top >= 2);  /* ECMAScript activation + Duktape.Thread.resume() activation */
74543                 DUK_ASSERT(thr->resumer->callstack_curr != NULL);
74544                 DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL);
74545                 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL &&
74546                            DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent)));  /* an ECMAScript function */
74547
74548                 resumer = thr->resumer;
74549
74550                 /* reset longjmp */
74551
74552                 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);  /* already set */
74553                 /* lj.value1 already set */
74554
74555                 duk_hthread_terminate(thr);  /* updates thread state, minimizes its allocations */
74556                 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
74557
74558                 thr->resumer = NULL;
74559                 DUK_HTHREAD_DECREF_NORZ(thr, resumer);
74560                 resumer->state = DUK_HTHREAD_STATE_RUNNING;
74561                 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
74562                 thr = resumer;
74563                 goto check_longjmp;
74564         }
74565
74566         case DUK_LJ_TYPE_BREAK:  /* pseudotypes, not used in actual longjmps */
74567         case DUK_LJ_TYPE_CONTINUE:
74568         case DUK_LJ_TYPE_RETURN:
74569         case DUK_LJ_TYPE_NORMAL:
74570         default: {
74571                 /* should never happen, but be robust */
74572                 DUK_D(DUK_DPRINT("caught unknown longjmp type %ld, treat as internal error", (long) thr->heap->lj.type));
74573                 goto convert_to_internal_error;
74574         }
74575
74576         }  /* end switch */
74577
74578         DUK_UNREACHABLE();
74579
74580  wipe_and_return:
74581         /* this is not strictly necessary, but helps debugging */
74582         thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
74583         thr->heap->lj.iserror = 0;
74584
74585         DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1);  /* side effects */
74586         DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2);  /* side effects */
74587
74588         DUK_GC_TORTURE(thr->heap);
74589
74590  just_return:
74591         return retval;
74592
74593  convert_to_internal_error:
74594         /* This could also be thrown internally (set the error, goto check_longjmp),
74595          * but it's better for internal errors to bubble outwards so that we won't
74596          * infinite loop in this catchpoint.
74597          */
74598         DUK_ERROR_INTERNAL(thr);
74599         DUK_WO_NORETURN(return 0;);
74600 }
74601
74602 /* Handle a BREAK/CONTINUE opcode.  Avoid using longjmp() for BREAK/CONTINUE
74603  * handling because it has a measurable performance impact in ordinary
74604  * environments and an extreme impact in Emscripten (GH-342).
74605  */
74606 DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_break_or_continue(duk_hthread *thr,
74607                                                                 duk_uint_t label_id,
74608                                                                 duk_small_uint_t lj_type) {
74609         duk_activation *act;
74610         duk_catcher *cat;
74611
74612         DUK_ASSERT(thr != NULL);
74613
74614         /* Find a matching label catcher or 'finally' catcher in
74615          * the same function, unwinding catchers as we go.
74616          *
74617          * A label catcher must always exist and will match unless
74618          * a 'finally' captures the break/continue first.  It is the
74619          * compiler's responsibility to ensure that labels are used
74620          * correctly.
74621          */
74622
74623         act = thr->callstack_curr;
74624         DUK_ASSERT(act != NULL);
74625
74626         for (;;) {
74627                 cat = act->cat;
74628                 if (cat == NULL) {
74629                         break;
74630                 }
74631
74632                 DUK_DDD(DUK_DDDPRINT("considering catcher %p: type=%ld label=%ld",
74633                                      (void *) cat,
74634                                      (long) DUK_CAT_GET_TYPE(cat),
74635                                      (long) DUK_CAT_GET_LABEL(cat)));
74636
74637                 /* XXX: bit mask test; FINALLY <-> TCF, single bit mask would suffice? */
74638
74639                 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
74640                     DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
74641                         duk_tval tv_tmp;
74642
74643                         DUK_TVAL_SET_U32(&tv_tmp, (duk_uint32_t) label_id);
74644                         duk__handle_finally(thr, &tv_tmp, lj_type);
74645
74646                         DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution"));
74647                         return;
74648                 }
74649                 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
74650                     (duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) {
74651                         duk__handle_label(thr, lj_type);
74652
74653                         DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution"));
74654                         return;
74655                 }
74656
74657                 duk_hthread_catcher_unwind_norz(thr, act);
74658         }
74659
74660         /* Should never happen, but be robust. */
74661         DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error"));
74662         DUK_ERROR_INTERNAL(thr);
74663         DUK_WO_NORETURN(return;);
74664 }
74665
74666 /* Handle a RETURN opcode.  Avoid using longjmp() for return handling because
74667  * it has a measurable performance impact in ordinary environments and an extreme
74668  * impact in Emscripten (GH-342).  Return value is on value stack top.
74669  */
74670 DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr, duk_activation *entry_act) {
74671         duk_tval *tv1;
74672         duk_tval *tv2;
74673 #if defined(DUK_USE_COROUTINE_SUPPORT)
74674         duk_hthread *resumer;
74675 #endif
74676         duk_activation *act;
74677         duk_catcher *cat;
74678
74679         /* We can directly access value stack here. */
74680
74681         DUK_ASSERT(thr != NULL);
74682         DUK_ASSERT(entry_act != NULL);
74683         DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
74684         tv1 = thr->valstack_top - 1;
74685         DUK_TVAL_CHKFAST_INPLACE_FAST(tv1);  /* fastint downgrade check for return values */
74686
74687         /*
74688          *  Four possible outcomes:
74689          *
74690          *    1. A 'finally' in the same function catches the 'return'.
74691          *       It may continue to propagate when 'finally' is finished,
74692          *       or it may be neutralized by 'finally' (both handled by
74693          *       ENDFIN).
74694          *
74695          *    2. The return happens at the entry level of the bytecode
74696          *       executor, so return from the executor (in C stack).
74697          *
74698          *    3. There is a calling (ECMAScript) activation in the call
74699          *       stack => return to it, in the same executor instance.
74700          *
74701          *    4. There is no calling activation, and the thread is
74702          *       terminated.  There is always a resumer in this case,
74703          *       which gets the return value similarly to a 'yield'
74704          *       (except that the current thread can no longer be
74705          *       resumed).
74706          */
74707
74708         DUK_ASSERT(thr != NULL);
74709         DUK_ASSERT(thr->callstack_top >= 1);
74710
74711         act = thr->callstack_curr;
74712         DUK_ASSERT(act != NULL);
74713
74714         for (;;) {
74715                 cat = act->cat;
74716                 if (cat == NULL) {
74717                         break;
74718                 }
74719
74720                 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
74721                     DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
74722                         DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
74723                         duk__handle_finally(thr, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
74724
74725                         DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution"));
74726                         return DUK__RETHAND_RESTART;
74727                 }
74728
74729                 duk_hthread_catcher_unwind_norz(thr, act);
74730         }
74731
74732         if (act == entry_act) {
74733                 /* Return to the bytecode executor caller who will unwind stacks
74734                  * and handle constructor post-processing.
74735                  * Return value is already on the stack top: [ ... retval ].
74736                  */
74737
74738                 DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
74739                 return DUK__RETHAND_FINISHED;
74740         }
74741
74742         if (thr->callstack_top >= 2) {
74743                 /* There is a caller; it MUST be an ECMAScript caller (otherwise it would
74744                  * match entry_act check).
74745                  */
74746                 DUK_DDD(DUK_DDDPRINT("return to ECMAScript caller, retval_byteoff=%ld, lj_value1=%!T",
74747                                      (long) (thr->callstack_curr->parent->retval_byteoff),
74748                                      (duk_tval *) &thr->heap->lj.value1));
74749
74750                 DUK_ASSERT(thr->callstack_curr != NULL);
74751                 DUK_ASSERT(thr->callstack_curr->parent != NULL);
74752                 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr->parent)));   /* must be ECMAScript */
74753
74754 #if defined(DUK_USE_ES6_PROXY)
74755                 if (thr->callstack_curr->flags & (DUK_ACT_FLAG_CONSTRUCT | DUK_ACT_FLAG_CONSTRUCT_PROXY)) {
74756                         duk_call_construct_postprocess(thr, thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT_PROXY);  /* side effects */
74757                 }
74758 #else
74759                 if (thr->callstack_curr->flags & DUK_ACT_FLAG_CONSTRUCT) {
74760                         duk_call_construct_postprocess(thr, 0);  /* side effects */
74761                 }
74762 #endif
74763
74764                 tv1 = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + thr->callstack_curr->parent->retval_byteoff);
74765                 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
74766                 tv2 = thr->valstack_top - 1;
74767                 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2);  /* side effects */
74768
74769                 /* Catch stack unwind happens inline in callstack unwind. */
74770                 duk_hthread_activation_unwind_norz(thr);
74771
74772                 duk__reconfig_valstack_ecma_return(thr);
74773
74774                 DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller"));
74775                 return DUK__RETHAND_RESTART;
74776         }
74777
74778 #if defined(DUK_USE_COROUTINE_SUPPORT)
74779         DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)"));
74780
74781         DUK_ASSERT(thr->resumer != NULL);
74782         DUK_ASSERT(thr->resumer->callstack_top >= 2);  /* ECMAScript activation + Duktape.Thread.resume() activation */
74783         DUK_ASSERT(thr->resumer->callstack_curr != NULL);
74784         DUK_ASSERT(thr->resumer->callstack_curr->parent != NULL);
74785         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr) != NULL &&
74786                         DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr)) &&
74787                         ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack_curr))->func == duk_bi_thread_resume);  /* Duktape.Thread.resume() */
74788         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent) != NULL &&
74789                         DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack_curr->parent)));  /* an ECMAScript function */
74790         DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
74791         DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
74792
74793         resumer = thr->resumer;
74794
74795         /* Share yield longjmp handler.
74796          *
74797          * This sequence of steps is a bit fragile (see GH-1845):
74798          * - We need the return value from 'thr' (resumed thread) value stack.
74799          *   The termination unwinds its value stack, losing the value.
74800          * - We need a refcounted reference for 'thr', which may only exist
74801          *   in the caller value stack.  We can't unwind or reconfigure the
74802          *   caller's value stack without potentially freeing 'thr'.
74803          *
74804          * Current approach is to capture the 'thr' return value and store
74805          * a reference to 'thr' in the caller value stack temporarily.  This
74806          * keeps 'thr' reachable until final yield/return handling which
74807          * removes the references atomatically.
74808          */
74809
74810         DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
74811         duk_hthread_activation_unwind_norz(resumer);  /* May remove last reference to 'thr', but is NORZ. */
74812         duk_push_tval(resumer, thr->valstack_top - 1);  /* Capture return value, side effect free. */
74813         duk_push_hthread(resumer, thr);  /* Make 'thr' reachable again, before side effects. */
74814
74815         duk_hthread_terminate(thr);  /* Updates thread state, minimizes its allocations. */
74816         thr->resumer = NULL;
74817         DUK_HTHREAD_DECREF(thr, resumer);
74818         DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
74819
74820         resumer->state = DUK_HTHREAD_STATE_RUNNING;
74821         DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
74822
74823         DUK_ASSERT(resumer->valstack_top - 2 >= resumer->valstack_bottom);
74824         duk__handle_yield(thr, resumer, resumer->valstack_top - 2);
74825         thr = NULL;  /* 'thr' invalidated by call */
74826
74827 #if 0
74828         thr = resumer;  /* not needed */
74829 #endif
74830
74831         DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer"));
74832         return DUK__RETHAND_RESTART;
74833 #else
74834         /* Without coroutine support this case should never happen. */
74835         DUK_ERROR_INTERNAL(thr);
74836         DUK_WO_NORETURN(return 0;);
74837 #endif
74838 }
74839
74840 /*
74841  *  Executor interrupt handling
74842  *
74843  *  The handler is called whenever the interrupt countdown reaches zero
74844  *  (or below).  The handler must perform whatever checks are activated,
74845  *  e.g. check for cumulative step count to impose an execution step
74846  *  limit or check for breakpoints or other debugger interaction.
74847  *
74848  *  When the actions are done, the handler must reinit the interrupt
74849  *  init and counter values.  The 'init' value must indicate how many
74850  *  bytecode instructions are executed before the next interrupt.  The
74851  *  counter must interface with the bytecode executor loop.  Concretely,
74852  *  the new init value is normally one higher than the new counter value.
74853  *  For instance, to execute exactly one bytecode instruction the init
74854  *  value is set to 1 and the counter to 0.  If an error is thrown by the
74855  *  interrupt handler, the counters are set to the same value (e.g. both
74856  *  to 0 to cause an interrupt when the next bytecode instruction is about
74857  *  to be executed after error handling).
74858  *
74859  *  Maintaining the init/counter value properly is important for accurate
74860  *  behavior.  For instance, executor step limit needs a cumulative step
74861  *  count which is simply computed as a sum of 'init' values.  This must
74862  *  work accurately even when single stepping.
74863  */
74864
74865 #if defined(DUK_USE_INTERRUPT_COUNTER)
74866
74867 #define DUK__INT_NOACTION    0    /* no specific action, resume normal execution */
74868 #define DUK__INT_RESTART     1    /* must "goto restart_execution", e.g. breakpoints changed */
74869
74870 #if defined(DUK_USE_DEBUGGER_SUPPORT)
74871 DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) {
74872         duk_activation *act;
74873         duk_breakpoint *bp;
74874         duk_breakpoint **bp_active;
74875         duk_uint_fast32_t line = 0;
74876         duk_bool_t process_messages;
74877         duk_bool_t processed_messages = 0;
74878
74879         DUK_ASSERT(thr->heap->dbg_processing == 0);  /* don't re-enter e.g. during Eval */
74880
74881         act = thr->callstack_curr;
74882         DUK_ASSERT(act != NULL);
74883
74884         /* It might seem that replacing 'thr->heap' with just 'heap' below
74885          * might be a good idea, but it increases code size slightly
74886          * (probably due to unnecessary spilling) at least on x64.
74887          */
74888
74889         /*
74890          *  Single opcode step check
74891          */
74892
74893         if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE) {
74894                 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by one opcode step"));
74895                 duk_debug_set_paused(thr->heap);
74896         }
74897
74898         /*
74899          *  Breakpoint and step state checks
74900          */
74901
74902         if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
74903             (thr->heap->dbg_pause_act == thr->callstack_curr)) {
74904                 line = duk_debug_curr_line(thr);
74905
74906                 if (act->prev_line != line) {
74907                         /* Stepped?  Step out is handled by callstack unwind. */
74908                         if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
74909                             (thr->heap->dbg_pause_act == thr->callstack_curr) &&
74910                             (line != thr->heap->dbg_pause_startline)) {
74911                                 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by line change, at line %ld",
74912                                                  (long) line));
74913                                 duk_debug_set_paused(thr->heap);
74914                         }
74915
74916                         /* Check for breakpoints only on line transition.
74917                          * Breakpoint is triggered when we enter the target
74918                          * line from a different line, and the previous line
74919                          * was within the same function.
74920                          *
74921                          * This condition is tricky: the condition used to be
74922                          * that transition to -or across- the breakpoint line
74923                          * triggered the breakpoint.  This seems intuitively
74924                          * better because it handles breakpoints on lines with
74925                          * no emitted opcodes; but this leads to the issue
74926                          * described in: https://github.com/svaarala/duktape/issues/263.
74927                          */
74928                         bp_active = thr->heap->dbg_breakpoints_active;
74929                         for (;;) {
74930                                 bp = *bp_active++;
74931                                 if (bp == NULL) {
74932                                         break;
74933                                 }
74934
74935                                 DUK_ASSERT(bp->filename != NULL);
74936                                 if (act->prev_line != bp->line && line == bp->line) {
74937                                         DUK_D(DUK_DPRINT("PAUSE TRIGGERED by breakpoint at %!O:%ld",
74938                                                          (duk_heaphdr *) bp->filename, (long) bp->line));
74939                                         duk_debug_set_paused(thr->heap);
74940                                 }
74941                         }
74942                 } else {
74943                         ;
74944                 }
74945
74946                 act->prev_line = (duk_uint32_t) line;
74947         }
74948
74949         /*
74950          *  Rate limit check for sending status update or peeking into
74951          *  the debug transport.  Both can be expensive operations that
74952          *  we don't want to do on every opcode.
74953          *
74954          *  Making sure the interval remains reasonable on a wide variety
74955          *  of targets and bytecode is difficult without a timestamp, so
74956          *  we use a Date-provided timestamp for the rate limit check.
74957          *  But since it's also expensive to get a timestamp, a bytecode
74958          *  counter is used to rate limit getting timestamps.
74959          */
74960
74961         process_messages = 0;
74962         if (thr->heap->dbg_state_dirty || DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->dbg_detaching) {
74963                 /* Enter message processing loop for sending Status notifys and
74964                  * to finish a pending detach.
74965                  */
74966                 process_messages = 1;
74967         }
74968
74969         /* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */
74970         DUK_ASSERT(thr->interrupt_init >= 0);
74971         thr->heap->dbg_exec_counter += (duk_uint_t) thr->interrupt_init;
74972         if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) {
74973                 /* Overflow of the execution counter is fine and doesn't break
74974                  * anything here.
74975                  */
74976
74977                 duk_double_t now, diff_last;
74978
74979                 thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter;
74980                 now = duk_time_get_monotonic_time(thr);
74981
74982                 diff_last = now - thr->heap->dbg_last_time;
74983                 if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) {
74984                         /* Monotonic time should not experience time jumps,
74985                          * but the provider may be missing and we're actually
74986                          * using ECMAScript time.  So, tolerate negative values
74987                          * so that a time jump works reasonably.
74988                          *
74989                          * Same interval is now used for status sending and
74990                          * peeking.
74991                          */
74992
74993                         thr->heap->dbg_last_time = now;
74994                         thr->heap->dbg_state_dirty = 1;
74995                         process_messages = 1;
74996                 }
74997         }
74998
74999         /*
75000          *  Process messages and send status if necessary.
75001          *
75002          *  If we're paused, we'll block for new messages.  If we're not
75003          *  paused, we'll process anything we can peek but won't block
75004          *  for more.  Detach (and re-attach) handling is all localized
75005          *  to duk_debug_process_messages() too.
75006          *
75007          *  Debugger writes outside the message loop may cause debugger
75008          *  detach1 phase to run, after which dbg_read_cb == NULL and
75009          *  dbg_detaching != 0.  The message loop will finish the detach
75010          *  by running detach2 phase, so enter the message loop also when
75011          *  detaching.
75012          */
75013
75014         if (process_messages) {
75015                 DUK_ASSERT(thr->heap->dbg_processing == 0);
75016                 processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
75017                 DUK_ASSERT(thr->heap->dbg_processing == 0);
75018         }
75019
75020         /* Continue checked execution if there are breakpoints or we're stepping.
75021          * Also use checked execution if paused flag is active - it shouldn't be
75022          * because the debug message loop shouldn't terminate if it was.  Step out
75023          * is handled by callstack unwind and doesn't need checked execution.
75024          * Note that debugger may have detached due to error or explicit request
75025          * above, so we must recheck attach status.
75026          */
75027
75028         if (duk_debug_is_attached(thr->heap)) {
75029                 DUK_ASSERT(act == thr->callstack_curr);
75030                 DUK_ASSERT(act != NULL);
75031                 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
75032                     (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) ||
75033                     ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
75034                      thr->heap->dbg_pause_act == thr->callstack_curr) ||
75035                      DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
75036                         *out_immediate = 1;
75037                 }
75038
75039                 /* If we processed any debug messages breakpoints may have
75040                  * changed; restart execution to re-check active breakpoints.
75041                  */
75042                 if (processed_messages) {
75043                         DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints"));
75044                         *out_interrupt_retval = DUK__INT_RESTART;
75045                 } else {
75046                         if (thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_ONE_OPCODE) {
75047                                 /* Set 'pause after one opcode' active only when we're
75048                                  * actually just about to execute code.
75049                                  */
75050                                 thr->heap->dbg_pause_flags |= DUK_PAUSE_FLAG_ONE_OPCODE_ACTIVE;
75051                         }
75052                 }
75053         } else {
75054                 DUK_D(DUK_DPRINT("debugger became detached, resume normal execution"));
75055         }
75056 }
75057 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
75058
75059 DUK_LOCAL DUK__NOINLINE_PERF DUK_COLD duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
75060         duk_int_t ctr;
75061         duk_activation *act;
75062         duk_hcompfunc *fun;
75063         duk_bool_t immediate = 0;
75064         duk_small_uint_t retval;
75065
75066         DUK_ASSERT(thr != NULL);
75067         DUK_ASSERT(thr->heap != NULL);
75068         DUK_ASSERT(thr->callstack_top > 0);
75069
75070 #if defined(DUK_USE_DEBUG)
75071         thr->heap->inst_count_interrupt += thr->interrupt_init;
75072         DUK_DD(DUK_DDPRINT("execution interrupt, counter=%ld, init=%ld, "
75073                            "instruction counts: executor=%ld, interrupt=%ld",
75074                            (long) thr->interrupt_counter, (long) thr->interrupt_init,
75075                            (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
75076 #endif
75077
75078         retval = DUK__INT_NOACTION;
75079         ctr = DUK_HTHREAD_INTCTR_DEFAULT;
75080
75081         /*
75082          *  Avoid nested calls.  Concretely this happens during debugging, e.g.
75083          *  when we eval() an expression.
75084          *
75085          *  Also don't interrupt if we're currently doing debug processing
75086          *  (which can be initiated outside the bytecode executor) as this
75087          *  may cause the debugger to be called recursively.  Check required
75088          *  for correct operation of throw intercept and other "exotic" halting
75089          * scenarios.
75090          */
75091
75092 #if defined(DUK_USE_DEBUGGER_SUPPORT)
75093         if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap) || thr->heap->dbg_processing) {
75094 #else
75095         if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap)) {
75096 #endif
75097                 DUK_DD(DUK_DDPRINT("nested executor interrupt, ignoring"));
75098
75099                 /* Set a high interrupt counter; the original executor
75100                  * interrupt invocation will rewrite before exiting.
75101                  */
75102                 thr->interrupt_init = ctr;
75103                 thr->interrupt_counter = ctr - 1;
75104                 return DUK__INT_NOACTION;
75105         }
75106         DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap);
75107
75108         act = thr->callstack_curr;
75109         DUK_ASSERT(act != NULL);
75110
75111         fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
75112         DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun));
75113
75114         DUK_UNREF(fun);
75115
75116 #if defined(DUK_USE_EXEC_TIMEOUT_CHECK)
75117         /*
75118          *  Execution timeout check
75119          */
75120
75121         if (DUK_USE_EXEC_TIMEOUT_CHECK(thr->heap->heap_udata)) {
75122                 /* Keep throwing an error whenever we get here.  The unusual values
75123                  * are set this way because no instruction is ever executed, we just
75124                  * throw an error until all try/catch/finally and other catchpoints
75125                  * have been exhausted.  Duktape/C code gets control at each protected
75126                  * call but whenever it enters back into Duktape the RangeError gets
75127                  * raised.  User exec timeout check must consistently indicate a timeout
75128                  * until we've fully bubbled out of Duktape.
75129                  */
75130                 DUK_D(DUK_DPRINT("execution timeout, throwing a RangeError"));
75131                 thr->interrupt_init = 0;
75132                 thr->interrupt_counter = 0;
75133                 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
75134                 DUK_ERROR_RANGE(thr, "execution timeout");
75135                 DUK_WO_NORETURN(return 0;);
75136         }
75137 #endif  /* DUK_USE_EXEC_TIMEOUT_CHECK */
75138
75139 #if defined(DUK_USE_DEBUGGER_SUPPORT)
75140         if (!thr->heap->dbg_processing &&
75141             (thr->heap->dbg_read_cb != NULL || thr->heap->dbg_detaching)) {
75142                 /* Avoid recursive re-entry; enter when we're attached or
75143                  * detaching (to finish off the pending detach).
75144                  */
75145                 duk__interrupt_handle_debugger(thr, &immediate, &retval);
75146                 DUK_ASSERT(act == thr->callstack_curr);
75147         }
75148 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
75149
75150         /*
75151          *  Update the interrupt counter
75152          */
75153
75154         if (immediate) {
75155                 /* Cause an interrupt after executing one instruction. */
75156                 ctr = 1;
75157         }
75158
75159         /* The counter value is one less than the init value: init value should
75160          * indicate how many instructions are executed before interrupt.  To
75161          * execute 1 instruction (after interrupt handler return), counter must
75162          * be 0.
75163          */
75164         DUK_ASSERT(ctr >= 1);
75165         thr->interrupt_init = ctr;
75166         thr->interrupt_counter = ctr - 1;
75167         DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
75168
75169         return retval;
75170 }
75171 #endif  /* DUK_USE_INTERRUPT_COUNTER */
75172
75173 /*
75174  *  Debugger handling for executor restart
75175  *
75176  *  Check for breakpoints, stepping, etc, and figure out if we should execute
75177  *  in checked or normal mode.  Note that we can't do this when an activation
75178  *  is created, because breakpoint status (and stepping status) may change
75179  *  later, so we must recheck every time we're executing an activation.
75180  *  This primitive should be side effect free to avoid changes during check.
75181  */
75182
75183 #if defined(DUK_USE_DEBUGGER_SUPPORT)
75184 DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompfunc *fun) {
75185         duk_heap *heap;
75186         duk_tval *tv_tmp;
75187         duk_hstring *filename;
75188         duk_small_uint_t bp_idx;
75189         duk_breakpoint **bp_active;
75190
75191         DUK_ASSERT(thr != NULL);
75192         DUK_ASSERT(act != NULL);
75193         DUK_ASSERT(fun != NULL);
75194
75195         heap = thr->heap;
75196         bp_active = heap->dbg_breakpoints_active;
75197         act->flags &= ~DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
75198
75199         tv_tmp = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) fun, DUK_HTHREAD_STRING_FILE_NAME(thr));
75200         if (tv_tmp && DUK_TVAL_IS_STRING(tv_tmp)) {
75201                 filename = DUK_TVAL_GET_STRING(tv_tmp);
75202
75203                 /* Figure out all active breakpoints.  A breakpoint is
75204                  * considered active if the current function's fileName
75205                  * matches the breakpoint's fileName, AND there is no
75206                  * inner function that has matching line numbers
75207                  * (otherwise a breakpoint would be triggered both
75208                  * inside and outside of the inner function which would
75209                  * be confusing).  Example:
75210                  *
75211                  *     function foo() {
75212                  *         print('foo');
75213                  *         function bar() {    <-.  breakpoints in these
75214                  *             print('bar');     |  lines should not affect
75215                  *         }                   <-'  foo() execution
75216                  *         bar();
75217                  *     }
75218                  *
75219                  * We need a few things that are only available when
75220                  * debugger support is enabled: (1) a line range for
75221                  * each function, and (2) access to the function
75222                  * template to access the inner functions (and their
75223                  * line ranges).
75224                  *
75225                  * It's important to have a narrow match for active
75226                  * breakpoints so that we don't enter checked execution
75227                  * when that's not necessary.  For instance, if we're
75228                  * running inside a certain function and there's
75229                  * breakpoint outside in (after the call site), we
75230                  * don't want to slow down execution of the function.
75231                  */
75232
75233                 for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) {
75234                         duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx;
75235                         duk_hobject **funcs, **funcs_end;
75236                         duk_hcompfunc *inner_fun;
75237                         duk_bool_t bp_match;
75238
75239                         if (bp->filename == filename &&
75240                             bp->line >= fun->start_line && bp->line <= fun->end_line) {
75241                                 bp_match = 1;
75242                                 DUK_DD(DUK_DDPRINT("breakpoint filename and line match: "
75243                                                    "%s:%ld vs. %s (line %ld vs. %ld-%ld)",
75244                                                    DUK_HSTRING_GET_DATA(bp->filename),
75245                                                    (long) bp->line,
75246                                                    DUK_HSTRING_GET_DATA(filename),
75247                                                    (long) bp->line,
75248                                                    (long) fun->start_line,
75249                                                    (long) fun->end_line));
75250
75251                                 funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun);
75252                                 funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, fun);
75253                                 while (funcs != funcs_end) {
75254                                         inner_fun = (duk_hcompfunc *) *funcs;
75255                                         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) inner_fun));
75256                                         if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) {
75257                                                 DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint"));
75258                                                 bp_match = 0;
75259                                                 break;
75260                                         }
75261                                         funcs++;
75262                                 }
75263
75264                                 if (bp_match) {
75265                                         /* No need to check for size of bp_active list,
75266                                          * it's always larger than maximum number of
75267                                          * breakpoints.
75268                                          */
75269                                         act->flags |= DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
75270                                         *bp_active = heap->dbg_breakpoints + bp_idx;
75271                                         bp_active++;
75272                                 }
75273                         }
75274                 }
75275         }
75276
75277         *bp_active = NULL;  /* terminate */
75278
75279         DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active)));
75280
75281         /* Force pause if we were doing "step into" in another activation. */
75282         if ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_FUNC_ENTRY) &&
75283             thr->heap->dbg_pause_act != thr->callstack_curr) {
75284                 DUK_D(DUK_DPRINT("PAUSE TRIGGERED by function entry"));
75285                 duk_debug_set_paused(thr->heap);
75286         }
75287
75288         /* Force interrupt right away if we're paused or in "checked mode".
75289          * Step out is handled by callstack unwind.
75290          */
75291         if ((act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
75292             DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ||
75293             ((thr->heap->dbg_pause_flags & DUK_PAUSE_FLAG_LINE_CHANGE) &&
75294              thr->heap->dbg_pause_act == thr->callstack_curr)) {
75295                 /* We'll need to interrupt early so recompute the init
75296                  * counter to reflect the number of bytecode instructions
75297                  * executed so that step counts for e.g. debugger rate
75298                  * limiting are accurate.
75299                  */
75300                 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
75301                 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
75302                 thr->interrupt_counter = 0;
75303         }
75304 }
75305 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
75306
75307 /*
75308  *  Opcode handlers for opcodes with a lot of code and which are relatively
75309  *  rare; NOINLINE to reduce amount of code in main bytecode dispatcher.
75310  */
75311
75312 DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_initset_initget(duk_hthread *thr, duk_uint_fast32_t ins) {
75313         duk_bool_t is_set = (DUK_DEC_OP(ins) == DUK_OP_INITSET);
75314         duk_uint_fast_t idx;
75315         duk_uint_t defprop_flags;
75316
75317         /* A -> object register (acts as a source)
75318          * BC -> BC+0 contains key, BC+1 closure (value)
75319          */
75320
75321         /* INITSET/INITGET are only used to initialize object literal keys.
75322          * There may be a previous propery in ES2015 because duplicate property
75323          * names are allowed.
75324          */
75325
75326         /* This could be made more optimal by accessing internals directly. */
75327
75328         idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
75329         duk_dup(thr, (duk_idx_t) (idx + 0));  /* key */
75330         duk_dup(thr, (duk_idx_t) (idx + 1));  /* getter/setter */
75331         if (is_set) {
75332                 defprop_flags = DUK_DEFPROP_HAVE_SETTER |
75333                                 DUK_DEFPROP_FORCE |
75334                                 DUK_DEFPROP_SET_ENUMERABLE |
75335                                 DUK_DEFPROP_SET_CONFIGURABLE;
75336         } else {
75337                 defprop_flags = DUK_DEFPROP_HAVE_GETTER |
75338                                 DUK_DEFPROP_FORCE |
75339                                 DUK_DEFPROP_SET_ENUMERABLE |
75340                                 DUK_DEFPROP_SET_CONFIGURABLE;
75341         }
75342         duk_def_prop(thr, (duk_idx_t) DUK_DEC_A(ins), defprop_flags);
75343 }
75344
75345 DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_trycatch(duk_hthread *thr, duk_uint_fast32_t ins, duk_instr_t *curr_pc) {
75346         duk_activation *act;
75347         duk_catcher *cat;
75348         duk_tval *tv1;
75349         duk_small_uint_fast_t a;
75350         duk_small_uint_fast_t bc;
75351
75352         /* A -> flags
75353          * BC -> reg_catch; base register for two registers used both during
75354          *       trycatch setup and when catch is triggered
75355          *
75356          *      If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
75357          *          reg_catch + 0: catch binding variable name (string).
75358          *          Automatic declarative environment is established for
75359          *          the duration of the 'catch' clause.
75360          *
75361          *      If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
75362          *          reg_catch + 0: with 'target value', which is coerced to
75363          *          an object and then used as a bindind object for an
75364          *          environment record.  The binding is initialized here, for
75365          *          the 'try' clause.
75366          *
75367          * Note that a TRYCATCH generated for a 'with' statement has no
75368          * catch or finally parts.
75369          */
75370
75371         /* XXX: TRYCATCH handling should be reworked to avoid creating
75372          * an explicit scope unless it is actually needed (e.g. function
75373          * instances or eval is executed inside the catch block).  This
75374          * rework is not trivial because the compiler doesn't have an
75375          * intermediate representation.  When the rework is done, the
75376          * opcode format can also be made more straightforward.
75377          */
75378
75379         /* XXX: side effect handling is quite awkward here */
75380
75381         DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
75382                              "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
75383                              (long) DUK_DEC_BC(ins),
75384                              (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
75385                              (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
75386                              (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
75387                              (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
75388                              (unsigned long) DUK_DEC_A(ins)));
75389
75390         a = DUK_DEC_A(ins);
75391         bc = DUK_DEC_BC(ins);
75392
75393         /* Registers 'bc' and 'bc + 1' are written in longjmp handling
75394          * and if their previous values (which are temporaries) become
75395          * unreachable -and- have a finalizer, there'll be a function
75396          * call during error handling which is not supported now (GH-287).
75397          * Ensure that both 'bc' and 'bc + 1' have primitive values to
75398          * guarantee no finalizer calls in error handling.  Scrubbing also
75399          * ensures finalizers for the previous values run here rather than
75400          * later.  Error handling related values are also written to 'bc'
75401          * and 'bc + 1' but those values never become unreachable during
75402          * error handling, so there's no side effect problem even if the
75403          * error value has a finalizer.
75404          */
75405         duk_dup(thr, (duk_idx_t) bc);  /* Stabilize value. */
75406         duk_to_undefined(thr, (duk_idx_t) bc);
75407         duk_to_undefined(thr, (duk_idx_t) (bc + 1));
75408
75409         /* Allocate catcher and populate it.  Doesn't have to
75410          * be fully atomic, but the catcher must be in a
75411          * consistent state if side effects (such as finalizer
75412          * calls) occur.
75413          */
75414
75415         cat = duk_hthread_catcher_alloc(thr);
75416         DUK_ASSERT(cat != NULL);
75417
75418         cat->flags = DUK_CAT_TYPE_TCF;
75419         cat->h_varname = NULL;
75420         cat->pc_base = (duk_instr_t *) curr_pc;  /* pre-incremented, points to first jump slot */
75421         cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
75422
75423         act = thr->callstack_curr;
75424         DUK_ASSERT(act != NULL);
75425         cat->parent = act->cat;
75426         act->cat = cat;
75427
75428         if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
75429                 cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
75430         }
75431         if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
75432                 cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
75433         }
75434         if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
75435                 DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
75436                 cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
75437                 tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
75438                 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
75439
75440                 /* borrowed reference; although 'tv1' comes from a register,
75441                  * its value was loaded using LDCONST so the constant will
75442                  * also exist and be reachable.
75443                  */
75444                 cat->h_varname = DUK_TVAL_GET_STRING(tv1);
75445         } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
75446                 duk_hobjenv *env;
75447                 duk_hobject *target;
75448
75449                 /* Delayed env initialization for activation (if needed). */
75450                 DUK_ASSERT(thr->callstack_top >= 1);
75451                 DUK_ASSERT(act == thr->callstack_curr);
75452                 DUK_ASSERT(act != NULL);
75453                 if (act->lex_env == NULL) {
75454                         DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
75455                         DUK_ASSERT(act->var_env == NULL);
75456
75457                         duk_js_init_activation_environment_records_delayed(thr, act);
75458                         DUK_ASSERT(act == thr->callstack_curr);
75459                         DUK_UNREF(act);  /* 'act' is no longer accessed, scanbuild fix */
75460                 }
75461                 DUK_ASSERT(act->lex_env != NULL);
75462                 DUK_ASSERT(act->var_env != NULL);
75463
75464                 /* Coerce 'with' target. */
75465                 target = duk_to_hobject(thr, -1);
75466                 DUK_ASSERT(target != NULL);
75467
75468                 /* Create an object environment; it is not pushed
75469                  * so avoid side effects very carefully until it is
75470                  * referenced.
75471                  */
75472                 env = duk_hobjenv_alloc(thr,
75473                                         DUK_HOBJECT_FLAG_EXTENSIBLE |
75474                                         DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV));
75475                 DUK_ASSERT(env != NULL);
75476                 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
75477                 env->target = target;  /* always provideThis=true */
75478                 DUK_HOBJECT_INCREF(thr, target);
75479                 env->has_this = 1;
75480                 DUK_ASSERT_HOBJENV_VALID(env);
75481                 DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iO", env));
75482
75483                 DUK_ASSERT(act == thr->callstack_curr);
75484                 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
75485                 DUK_ASSERT(act->lex_env != NULL);
75486                 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, act->lex_env);
75487                 act->lex_env = (duk_hobject *) env;  /* Now reachable. */
75488                 DUK_HOBJECT_INCREF(thr, (duk_hobject *) env);
75489                 /* Net refcount change to act->lex_env is 0: incref for env's
75490                  * prototype, decref for act->lex_env overwrite.
75491                  */
75492
75493                 /* Set catcher lex_env active (affects unwind)
75494                  * only when the whole setup is complete.
75495                  */
75496                 cat = act->cat;  /* XXX: better to relookup? not mandatory because 'cat' is stable */
75497                 cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
75498         } else {
75499                 ;
75500         }
75501
75502         DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, pc_base=%ld, "
75503                              "idx_base=%ld, h_varname=%!O",
75504                              (unsigned long) cat->flags,
75505                              (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
75506
75507         duk_pop_unsafe(thr);
75508 }
75509
75510 DUK_LOCAL DUK__NOINLINE_PERF duk_instr_t *duk__handle_op_endtry(duk_hthread *thr, duk_uint_fast32_t ins) {
75511         duk_activation *act;
75512         duk_catcher *cat;
75513         duk_tval *tv1;
75514         duk_instr_t *pc_base;
75515
75516         DUK_UNREF(ins);
75517
75518         DUK_ASSERT(thr->callstack_top >= 1);
75519         act = thr->callstack_curr;
75520         DUK_ASSERT(act != NULL);
75521         cat = act->cat;
75522         DUK_ASSERT(cat != NULL);
75523         DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_TCF);
75524
75525         DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
75526         DUK_CAT_CLEAR_CATCH_ENABLED(cat);
75527
75528         pc_base = cat->pc_base;
75529
75530         if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
75531                 DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
75532
75533                 tv1 = thr->valstack + cat->idx_base;
75534                 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
75535                 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1);  /* side effects */
75536                 tv1 = NULL;
75537
75538                 tv1 = thr->valstack + cat->idx_base + 1;
75539                 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
75540                 DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL);  /* side effects */
75541                 tv1 = NULL;
75542
75543                 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
75544         } else {
75545                 DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
75546
75547                 duk_hthread_catcher_unwind_norz(thr, act);  /* lexenv may be set for 'with' binding */
75548                 /* no need to unwind callstack */
75549         }
75550
75551         return pc_base + 1;  /* new curr_pc value */
75552 }
75553
75554 DUK_LOCAL DUK__NOINLINE_PERF duk_instr_t *duk__handle_op_endcatch(duk_hthread *thr, duk_uint_fast32_t ins) {
75555         duk_activation *act;
75556         duk_catcher *cat;
75557         duk_tval *tv1;
75558         duk_instr_t *pc_base;
75559
75560         DUK_UNREF(ins);
75561
75562         DUK_ASSERT(thr->callstack_top >= 1);
75563         act = thr->callstack_curr;
75564         DUK_ASSERT(act != NULL);
75565         cat = act->cat;
75566         DUK_ASSERT(cat != NULL);
75567         DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));  /* cleared before entering catch part */
75568
75569         if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
75570                 duk_hobject *prev_env;
75571
75572                 /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
75573                 DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
75574                 DUK_ASSERT(act->lex_env != NULL);
75575
75576                 DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
75577
75578                 prev_env = act->lex_env;
75579                 DUK_ASSERT(prev_env != NULL);
75580                 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
75581                 DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
75582                 DUK_HOBJECT_INCREF(thr, act->lex_env);
75583                 DUK_HOBJECT_DECREF(thr, prev_env);  /* side effects */
75584
75585                 DUK_ASSERT(act == thr->callstack_curr);
75586                 DUK_ASSERT(act != NULL);
75587         }
75588
75589         pc_base = cat->pc_base;
75590
75591         if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
75592                 DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
75593
75594                 tv1 = thr->valstack + cat->idx_base;
75595                 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
75596                 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1);  /* side effects */
75597                 tv1 = NULL;
75598
75599                 tv1 = thr->valstack + cat->idx_base + 1;
75600                 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
75601                 DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL);  /* side effects */
75602                 tv1 = NULL;
75603
75604                 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
75605         } else {
75606                 DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
75607
75608                 duk_hthread_catcher_unwind_norz(thr, act);
75609                 /* no need to unwind callstack */
75610         }
75611
75612         return pc_base + 1;  /* new curr_pc value */
75613 }
75614
75615 DUK_LOCAL DUK__NOINLINE_PERF duk_small_uint_t duk__handle_op_endfin(duk_hthread *thr, duk_uint_fast32_t ins, duk_activation *entry_act) {
75616         duk_activation *act;
75617         duk_tval *tv1;
75618         duk_uint_t reg_catch;
75619         duk_small_uint_t cont_type;
75620         duk_small_uint_t ret_result;
75621
75622         DUK_ASSERT(thr->ptr_curr_pc == NULL);
75623         DUK_ASSERT(thr->callstack_top >= 1);
75624         act = thr->callstack_curr;
75625         DUK_ASSERT(act != NULL);
75626         reg_catch = DUK_DEC_ABC(ins);
75627
75628         /* CATCH flag may be enabled or disabled here; it may be enabled if
75629          * the statement has a catch block but the try block does not throw
75630          * an error.
75631          */
75632
75633         DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
75634                              (duk_tval *) (thr->valstack_bottom + reg_catch + 0),
75635                              (duk_tval *) (thr->valstack_bottom + reg_catch + 1)));
75636
75637         tv1 = thr->valstack_bottom + reg_catch + 1;  /* type */
75638         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
75639 #if defined(DUK_USE_FASTINT)
75640         DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
75641         cont_type = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
75642 #else
75643         cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
75644 #endif
75645
75646         tv1--;  /* value */
75647
75648         switch (cont_type) {
75649         case DUK_LJ_TYPE_NORMAL: {
75650                 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
75651                                      "dismantle catcher, resume execution after ENDFIN"));
75652
75653                 duk_hthread_catcher_unwind_norz(thr, act);
75654                 /* no need to unwind callstack */
75655                 return 0;  /* restart execution */
75656         }
75657         case DUK_LJ_TYPE_RETURN: {
75658                 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
75659                                      "catcher, handle return, lj.value1=%!T", tv1));
75660
75661                 /* Not necessary to unwind catch stack: return handling will
75662                  * do it.  The finally flag of 'cat' is no longer set.  The
75663                  * catch flag may be set, but it's not checked by return handling.
75664                  */
75665
75666                 duk_push_tval(thr, tv1);
75667                 ret_result = duk__handle_return(thr, entry_act);
75668                 if (ret_result == DUK__RETHAND_RESTART) {
75669                         return 0;  /* restart execution */
75670                 }
75671                 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
75672
75673                 DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
75674                 return 1;  /* exit executor */
75675         }
75676         case DUK_LJ_TYPE_BREAK:
75677         case DUK_LJ_TYPE_CONTINUE: {
75678                 duk_uint_t label_id;
75679                 duk_small_uint_t lj_type;
75680
75681                 /* Not necessary to unwind catch stack: break/continue
75682                  * handling will do it.  The finally flag of 'cat' is
75683                  * no longer set.  The catch flag may be set, but it's
75684                  * not checked by break/continue handling.
75685                  */
75686
75687                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
75688 #if defined(DUK_USE_FASTINT)
75689                 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
75690                 label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
75691 #else
75692                 label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
75693 #endif
75694                 lj_type = cont_type;
75695                 duk__handle_break_or_continue(thr, label_id, lj_type);
75696                 return 0;  /* restart execution */
75697         }
75698         default: {
75699                 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
75700                                      "dismantle catcher, re-throw error",
75701                                      (long) cont_type));
75702
75703                 duk_err_setup_ljstate1(thr, (duk_small_uint_t) cont_type, tv1);
75704                 /* No debugger Throw notify check on purpose (rethrow). */
75705
75706                 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* always in executor */
75707                 duk_err_longjmp(thr);
75708                 DUK_UNREACHABLE();
75709         }
75710         }
75711
75712         DUK_UNREACHABLE();
75713         return 0;
75714 }
75715
75716 DUK_LOCAL DUK__NOINLINE_PERF void duk__handle_op_initenum(duk_hthread *thr, duk_uint_fast32_t ins) {
75717         duk_small_uint_t b;
75718         duk_small_uint_t c;
75719
75720         /*
75721          *  Enumeration semantics come from for-in statement, E5 Section 12.6.4.
75722          *  If called with 'null' or 'undefined', this opcode returns 'null' as
75723          *  the enumerator, which is special cased in NEXTENUM.  This simplifies
75724          *  the compiler part
75725          */
75726
75727         /* B -> register for writing enumerator object
75728          * C -> value to be enumerated (register)
75729          */
75730         b = DUK_DEC_B(ins);
75731         c = DUK_DEC_C(ins);
75732
75733         if (duk_is_null_or_undefined(thr, (duk_idx_t) c)) {
75734                 duk_push_null(thr);
75735                 duk_replace(thr, (duk_idx_t) b);
75736         } else {
75737                 duk_dup(thr, (duk_idx_t) c);
75738                 duk_to_object(thr, -1);
75739                 duk_hobject_enumerator_create(thr, 0 /*enum_flags*/);  /* [ ... val ] --> [ ... enum ] */
75740                 duk_replace(thr, (duk_idx_t) b);
75741         }
75742 }
75743
75744 DUK_LOCAL DUK__NOINLINE_PERF duk_small_uint_t duk__handle_op_nextenum(duk_hthread *thr, duk_uint_fast32_t ins) {
75745         duk_small_uint_t b;
75746         duk_small_uint_t c;
75747         duk_small_uint_t pc_skip = 0;
75748
75749         /*
75750          *  NEXTENUM checks whether the enumerator still has unenumerated
75751          *  keys.  If so, the next key is loaded to the target register
75752          *  and the next instruction is skipped.  Otherwise the next instruction
75753          *  will be executed, jumping out of the enumeration loop.
75754          */
75755
75756         /* B -> target register for next key
75757          * C -> enum register
75758          */
75759         b = DUK_DEC_B(ins);
75760         c = DUK_DEC_C(ins);
75761
75762         DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
75763                              (duk_tval *) duk_get_tval(thr, (duk_idx_t) b),
75764                              (duk_tval *) duk_get_tval(thr, (duk_idx_t) c)));
75765
75766         if (duk_is_object(thr, (duk_idx_t) c)) {
75767                 /* XXX: assert 'c' is an enumerator */
75768                 duk_dup(thr, (duk_idx_t) c);
75769                 if (duk_hobject_enumerator_next(thr, 0 /*get_value*/)) {
75770                         /* [ ... enum ] -> [ ... next_key ] */
75771                         DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
75772                                              (duk_tval *) duk_get_tval(thr, -1)));
75773                         pc_skip = 1;
75774                 } else {
75775                         /* [ ... enum ] -> [ ... ] */
75776                         DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
75777                         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));  /* valstack policy */
75778                         thr->valstack_top++;
75779                 }
75780                 duk_replace(thr, (duk_idx_t) b);
75781         } else {
75782                 /* 'null' enumerator case -> behave as with an empty enumerator */
75783                 DUK_ASSERT(duk_is_null(thr, (duk_idx_t) c));
75784                 DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
75785         }
75786
75787         return pc_skip;
75788 }
75789
75790 /*
75791  *  Call handling helpers.
75792  */
75793
75794 DUK_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) {
75795         duk_bool_t rc;
75796
75797         duk_set_top_unsafe(thr, (duk_idx_t) (idx + nargs + 2));   /* [ ... func this arg1 ... argN ] */
75798
75799         /* Attempt an Ecma-to-Ecma call setup.  If the call
75800          * target is (directly or indirectly) Reflect.construct(),
75801          * the call may change into a constructor call on the fly.
75802          */
75803         rc = (duk_bool_t) duk_handle_call_unprotected(thr, idx, call_flags);
75804         if (rc != 0) {
75805                 /* Ecma-to-ecma call possible, may or may not
75806                  * be a tail call.  Avoid C recursion by
75807                  * reusing current executor instance.
75808                  */
75809                 DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
75810                 /* curr_pc synced by duk_handle_call_unprotected() */
75811                 DUK_ASSERT(thr->ptr_curr_pc == NULL);
75812                 return rc;
75813         } else {
75814                 /* Call was handled inline. */
75815         }
75816         DUK_ASSERT(thr->ptr_curr_pc != NULL);
75817         return rc;
75818 }
75819
75820 /*
75821  *  ECMAScript bytecode executor.
75822  *
75823  *  Resume execution for the current thread from its current activation.
75824  *  Returns when execution would return from the entry level activation,
75825  *  leaving a single return value on top of the stack.  Function calls
75826  *  and thread resumptions are handled internally.  If an error occurs,
75827  *  a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level
75828  *  setjmp() jmpbuf.
75829  *
75830  *  ECMAScript function calls and coroutine resumptions are handled
75831  *  internally (by the outer executor function) without recursive C calls.
75832  *  Other function calls are handled using duk_handle_call(), increasing
75833  *  C recursion depth.
75834  *
75835  *  Abrupt completions (= long control tranfers) are handled either
75836  *  directly by reconfiguring relevant stacks and restarting execution,
75837  *  or via a longjmp.  Longjmp-free handling is preferable for performance
75838  *  (especially Emscripten performance), and is used for: break, continue,
75839  *  and return.
75840  *
75841  *  For more detailed notes, see doc/execution.rst.
75842  *
75843  *  Also see doc/code-issues.rst for discussion of setjmp(), longjmp(),
75844  *  and volatile.
75845  */
75846
75847 /* Presence of 'fun' is config based, there's a marginal performance
75848  * difference and the best option is architecture dependent.
75849  */
75850 #if defined(DUK_USE_EXEC_FUN_LOCAL)
75851 #define DUK__FUN()          fun
75852 #else
75853 #define DUK__FUN()          ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack_curr))
75854 #endif
75855
75856 /* Strict flag. */
75857 #define DUK__STRICT()       ((duk_small_uint_t) DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
75858
75859 /* Reg/const access macros: these are very footprint and performance sensitive
75860  * so modify with care.  Arguments are sometimes evaluated multiple times which
75861  * is not ideal.
75862  */
75863 #define DUK__REG(x)         (*(thr->valstack_bottom + (x)))
75864 #define DUK__REGP(x)        (thr->valstack_bottom + (x))
75865 #define DUK__CONST(x)       (*(consts + (x)))
75866 #define DUK__CONSTP(x)      (consts + (x))
75867
75868 /* Reg/const access macros which take the 32-bit instruction and avoid an
75869  * explicit field decoding step by using shifts and masks.  These must be
75870  * kept in sync with duk_js_bytecode.h.  The shift/mask values are chosen
75871  * so that 'ins' can be shifted and masked and used as a -byte- offset
75872  * instead of a duk_tval offset which needs further shifting (which is an
75873  * issue on some, but not all, CPUs).
75874  */
75875 #define DUK__RCBIT_B           DUK_BC_REGCONST_B
75876 #define DUK__RCBIT_C           DUK_BC_REGCONST_C
75877 #if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE)
75878 #if defined(DUK_USE_PACKED_TVAL)
75879 #define DUK__TVAL_SHIFT        3  /* sizeof(duk_tval) == 8 */
75880 #else
75881 #define DUK__TVAL_SHIFT        4  /* sizeof(duk_tval) == 16; not always the case so also asserted for */
75882 #endif
75883 #define DUK__SHIFT_A           (DUK_BC_SHIFT_A - DUK__TVAL_SHIFT)
75884 #define DUK__SHIFT_B           (DUK_BC_SHIFT_B - DUK__TVAL_SHIFT)
75885 #define DUK__SHIFT_C           (DUK_BC_SHIFT_C - DUK__TVAL_SHIFT)
75886 #define DUK__SHIFT_BC          (DUK_BC_SHIFT_BC - DUK__TVAL_SHIFT)
75887 #define DUK__MASK_A            (DUK_BC_UNSHIFTED_MASK_A << DUK__TVAL_SHIFT)
75888 #define DUK__MASK_B            (DUK_BC_UNSHIFTED_MASK_B << DUK__TVAL_SHIFT)
75889 #define DUK__MASK_C            (DUK_BC_UNSHIFTED_MASK_C << DUK__TVAL_SHIFT)
75890 #define DUK__MASK_BC           (DUK_BC_UNSHIFTED_MASK_BC << DUK__TVAL_SHIFT)
75891 #define DUK__BYTEOFF_A(ins)    (((ins) >> DUK__SHIFT_A) & DUK__MASK_A)
75892 #define DUK__BYTEOFF_B(ins)    (((ins) >> DUK__SHIFT_B) & DUK__MASK_B)
75893 #define DUK__BYTEOFF_C(ins)    (((ins) >> DUK__SHIFT_C) & DUK__MASK_C)
75894 #define DUK__BYTEOFF_BC(ins)   (((ins) >> DUK__SHIFT_BC) & DUK__MASK_BC)
75895
75896 #define DUK__REGP_A(ins)       ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_A((ins))))
75897 #define DUK__REGP_B(ins)       ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_B((ins))))
75898 #define DUK__REGP_C(ins)       ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_C((ins))))
75899 #define DUK__REGP_BC(ins)      ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_BC((ins))))
75900 #define DUK__CONSTP_A(ins)     ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_A((ins))))
75901 #define DUK__CONSTP_B(ins)     ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_B((ins))))
75902 #define DUK__CONSTP_C(ins)     ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_C((ins))))
75903 #define DUK__CONSTP_BC(ins)    ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_BC((ins))))
75904 #define DUK__REGCONSTP_B(ins)  ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_B((ins))))
75905 #define DUK__REGCONSTP_C(ins)  ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_C((ins))))
75906 #else  /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
75907 /* Safe alternatives, no assumption about duk_tval size. */
75908 #define DUK__REGP_A(ins)       DUK__REGP(DUK_DEC_A((ins)))
75909 #define DUK__REGP_B(ins)       DUK__REGP(DUK_DEC_B((ins)))
75910 #define DUK__REGP_C(ins)       DUK__REGP(DUK_DEC_C((ins)))
75911 #define DUK__REGP_BC(ins)      DUK__REGP(DUK_DEC_BC((ins)))
75912 #define DUK__CONSTP_A(ins)     DUK__CONSTP(DUK_DEC_A((ins)))
75913 #define DUK__CONSTP_B(ins)     DUK__CONSTP(DUK_DEC_B((ins)))
75914 #define DUK__CONSTP_C(ins)     DUK__CONSTP(DUK_DEC_C((ins)))
75915 #define DUK__CONSTP_BC(ins)    DUK__CONSTP(DUK_DEC_BC((ins)))
75916 #define DUK__REGCONSTP_B(ins)  ((((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK_DEC_B((ins)))
75917 #define DUK__REGCONSTP_C(ins)  ((((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK_DEC_C((ins)))
75918 #endif  /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
75919
75920 #if defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS)
75921 #define DUK__INTERNAL_ERROR(msg)  do { \
75922                 DUK_ERROR_ERROR(thr, (msg)); \
75923                 DUK_WO_NORETURN(return;); \
75924         } while (0)
75925 #else
75926 #define DUK__INTERNAL_ERROR(msg)  do { \
75927                 goto internal_error; \
75928         } while (0)
75929 #endif
75930
75931 #define DUK__SYNC_CURR_PC()  do { \
75932                 duk_activation *duk__act; \
75933                 duk__act = thr->callstack_curr; \
75934                 duk__act->curr_pc = curr_pc; \
75935         } while (0)
75936 #define DUK__SYNC_AND_NULL_CURR_PC()  do { \
75937                 duk_activation *duk__act; \
75938                 duk__act = thr->callstack_curr; \
75939                 duk__act->curr_pc = curr_pc; \
75940                 thr->ptr_curr_pc = NULL; \
75941         } while (0)
75942
75943 #if defined(DUK_USE_EXEC_PREFER_SIZE)
75944 #define DUK__LOOKUP_INDIRECT(idx) do { \
75945                 (idx) = (duk_uint_fast_t) duk_get_uint(thr, (duk_idx_t) (idx)); \
75946         } while (0)
75947 #elif defined(DUK_USE_FASTINT)
75948 #define DUK__LOOKUP_INDIRECT(idx) do { \
75949                 duk_tval *tv_ind; \
75950                 tv_ind = DUK__REGP((idx)); \
75951                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
75952                 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_ind));  /* compiler guarantees */ \
75953                 (idx) = (duk_uint_fast_t) DUK_TVAL_GET_FASTINT_U32(tv_ind); \
75954         } while (0)
75955 #else
75956 #define DUK__LOOKUP_INDIRECT(idx) do { \
75957                 duk_tval *tv_ind; \
75958                 tv_ind = DUK__REGP(idx); \
75959                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
75960                 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind); \
75961         } while (0)
75962 #endif
75963
75964 DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
75965                                           duk_activation *entry_act,
75966                                           duk_int_t entry_call_recursion_depth,
75967                                           duk_jmpbuf *entry_jmpbuf_ptr) {
75968         duk_small_uint_t lj_ret;
75969
75970         /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
75971          * before longjmp.
75972          */
75973         DUK_ASSERT(heap->curr_thread != NULL);
75974         DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
75975
75976         /* XXX: signalling the need to shrink check (only if unwound) */
75977
75978         /* Must be restored here to handle e.g. yields properly. */
75979         heap->call_recursion_depth = entry_call_recursion_depth;
75980
75981         /* Switch to caller's setjmp() catcher so that if an error occurs
75982          * during error handling, it is always propagated outwards instead
75983          * of causing an infinite loop in our own handler.
75984          */
75985         heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
75986
75987         lj_ret = duk__handle_longjmp(heap->curr_thread, entry_act);
75988
75989         /* Error handling complete, remove side effect protections.
75990          */
75991 #if defined(DUK_USE_ASSERTIONS)
75992         DUK_ASSERT(heap->error_not_allowed == 1);
75993         heap->error_not_allowed = 0;
75994 #endif
75995         DUK_ASSERT(heap->pf_prevent_count > 0);
75996         heap->pf_prevent_count--;
75997         DUK_DD(DUK_DDPRINT("executor error handled, pf_prevent_count updated to %ld", (long) heap->pf_prevent_count));
75998
75999         if (lj_ret == DUK__LONGJMP_RESTART) {
76000                 /* Restart bytecode execution, possibly with a changed thread. */
76001                 DUK_REFZERO_CHECK_SLOW(heap->curr_thread);
76002         } else {
76003                 /* If an error is propagated, don't run refzero checks here.
76004                  * The next catcher will deal with that.  Pf_prevent_count
76005                  * will be re-bumped by the longjmp.
76006                  */
76007
76008                 DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);  /* Rethrow error to calling state. */
76009                 DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);  /* Longjmp handling has restored jmpbuf_ptr. */
76010
76011                 /* Thread may have changed, e.g. YIELD converted to THROW. */
76012                 duk_err_longjmp(heap->curr_thread);
76013                 DUK_UNREACHABLE();
76014         }
76015 }
76016
76017 /* Outer executor with setjmp/longjmp handling. */
76018 DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
76019         /* Entry level info. */
76020         duk_hthread *entry_thread;
76021         duk_activation *entry_act;
76022         duk_int_t entry_call_recursion_depth;
76023         duk_jmpbuf *entry_jmpbuf_ptr;
76024         duk_jmpbuf our_jmpbuf;
76025         duk_heap *heap;
76026
76027         DUK_ASSERT(exec_thr != NULL);
76028         DUK_ASSERT(exec_thr->heap != NULL);
76029         DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
76030         DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr);
76031         DUK_ASSERT(exec_thr->callstack_top >= 1);  /* at least one activation, ours */
76032         DUK_ASSERT(exec_thr->callstack_curr != NULL);
76033         DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack_curr) != NULL);
76034         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack_curr)));
76035
76036         DUK_GC_TORTURE(exec_thr->heap);
76037
76038         entry_thread = exec_thr;
76039         heap = entry_thread->heap;
76040         entry_act = entry_thread->callstack_curr;
76041         DUK_ASSERT(entry_act != NULL);
76042         entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
76043         entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
76044
76045         /*
76046          *  Note: we currently assume that the setjmp() catchpoint is
76047          *  not re-entrant (longjmp() cannot be called more than once
76048          *  for a single setjmp()).
76049          *
76050          *  See doc/code-issues.rst for notes on variable assignment
76051          *  before and after setjmp().
76052          */
76053
76054         for (;;) {
76055                 heap->lj.jmpbuf_ptr = &our_jmpbuf;
76056                 DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
76057
76058 #if defined(DUK_USE_CPP_EXCEPTIONS)
76059                 try {
76060 #else
76061                 DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf);
76062                 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
76063 #endif
76064                         /* Execute bytecode until returned or longjmp(). */
76065                         duk__js_execute_bytecode_inner(entry_thread, entry_act);
76066
76067                         /* Successful return: restore jmpbuf and return to caller. */
76068                         heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
76069
76070                         return;
76071 #if defined(DUK_USE_CPP_EXCEPTIONS)
76072                 } catch (duk_internal_exception &exc) {
76073 #else
76074                 } else {
76075 #endif
76076 #if defined(DUK_USE_CPP_EXCEPTIONS)
76077                         DUK_UNREF(exc);
76078 #endif
76079                         DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
76080                         DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
76081
76082                         duk__handle_executor_error(heap,
76083                                                    entry_act,
76084                                                    entry_call_recursion_depth,
76085                                                    entry_jmpbuf_ptr);
76086                 }
76087 #if defined(DUK_USE_CPP_EXCEPTIONS)
76088                 catch (duk_fatal_exception &exc) {
76089                         DUK_D(DUK_DPRINT("rethrow duk_fatal_exception"));
76090                         throw;
76091                 } catch (std::exception &exc) {
76092                         const char *what = exc.what();
76093                         if (!what) {
76094                                 what = "unknown";
76095                         }
76096                         DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
76097                         DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
76098                         try {
76099                                 DUK_ASSERT(heap->curr_thread != NULL);
76100                                 DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
76101                                 DUK_WO_NORETURN(return;);
76102                         } catch (duk_internal_exception exc) {
76103                                 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
76104                                 DUK_UNREF(exc);
76105                                 duk__handle_executor_error(heap,
76106                                                            entry_act,
76107                                                            entry_call_recursion_depth,
76108                                                            entry_jmpbuf_ptr);
76109                         }
76110                 } catch (...) {
76111                         DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
76112                         DUK_STATS_INC(exec_thr->heap, stats_exec_throw);
76113                         try {
76114                                 DUK_ASSERT(heap->curr_thread != NULL);
76115                                 DUK_ERROR_TYPE(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)");
76116                                 DUK_WO_NORETURN(return;);
76117                         } catch (duk_internal_exception exc) {
76118                                 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
76119                                 DUK_UNREF(exc);
76120                                 duk__handle_executor_error(heap,
76121                                                            entry_act,
76122                                                            entry_call_recursion_depth,
76123                                                            entry_jmpbuf_ptr);
76124                         }
76125                 }
76126 #endif
76127         }
76128
76129         DUK_WO_NORETURN(return;);
76130 }
76131
76132 /* Inner executor, performance critical. */
76133 DUK_LOCAL DUK_NOINLINE DUK_HOT void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_activation *entry_act) {
76134         /* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
76135          * Critical for performance.  It would be safest to make this volatile,
76136          * but that eliminates performance benefits; aliasing guarantees
76137          * should be enough though.
76138          */
76139         duk_instr_t *curr_pc;         /* bytecode has a stable pointer */
76140
76141         /* Hot variables for interpretation.  Critical for performance,
76142          * but must add sparingly to minimize register shuffling.
76143          */
76144         duk_hthread *thr;             /* stable */
76145         duk_tval *consts;             /* stable */
76146         duk_uint_fast32_t ins;
76147         /* 'funcs' is quite rarely used, so no local for it */
76148 #if defined(DUK_USE_EXEC_FUN_LOCAL)
76149         duk_hcompfunc *fun;
76150 #else
76151         /* 'fun' is quite rarely used, so no local for it */
76152 #endif
76153
76154 #if defined(DUK_USE_INTERRUPT_COUNTER)
76155         duk_int_t int_ctr;
76156 #endif
76157
76158 #if defined(DUK_USE_ASSERTIONS)
76159         duk_size_t valstack_top_base;    /* valstack top, should match before interpreting each op (no leftovers) */
76160 #endif
76161
76162         /* Optimized reg/const access macros assume sizeof(duk_tval) to be
76163          * either 8 or 16.  Heap allocation checks this even without asserts
76164          * enabled now because it can't be autodetected in duk_config.h.
76165          */
76166 #if 1
76167 #if defined(DUK_USE_PACKED_TVAL)
76168         DUK_ASSERT(sizeof(duk_tval) == 8);
76169 #else
76170         DUK_ASSERT(sizeof(duk_tval) == 16);
76171 #endif
76172 #endif
76173
76174         DUK_GC_TORTURE(entry_thread->heap);
76175
76176         /*
76177          *  Restart execution by reloading thread state.
76178          *
76179          *  Note that 'thr' and any thread configuration may have changed,
76180          *  so all local variables are suspect and we need to reinitialize.
76181          *
76182          *  The number of local variables should be kept to a minimum: if
76183          *  the variables are spilled, they will need to be loaded from
76184          *  memory anyway.
76185          *
76186          *  Any 'goto restart_execution;' code path in opcode dispatch must
76187          *  ensure 'curr_pc' is synced back to act->curr_pc before the goto
76188          *  takes place.
76189          *
76190          *  The interpreter must be very careful with memory pointers, as
76191          *  many pointers are not guaranteed to be 'stable' and may be
76192          *  reallocated and relocated on-the-fly quite easily (e.g. by a
76193          *  memory allocation or a property access).
76194          *
76195          *  The following are assumed to have stable pointers:
76196          *    - the current thread
76197          *    - the current function
76198          *    - the bytecode, constant table, inner function table of the
76199          *      current function (as they are a part of the function allocation)
76200          *
76201          *  The following are assumed to have semi-stable pointers:
76202          *    - the current activation entry: stable as long as callstack
76203          *      is not changed (reallocated by growing or shrinking), or
76204          *      by any garbage collection invocation (through finalizers)
76205          *    - Note in particular that ANY DECREF can invalidate the
76206          *      activation pointer, so for the most part a fresh lookup
76207          *      is required
76208          *
76209          *  The following are not assumed to have stable pointers at all:
76210          *    - the value stack (registers) of the current thread
76211          *
76212          *  See execution.rst for discussion.
76213          */
76214
76215  restart_execution:
76216
76217         /* Lookup current thread; use the stable 'entry_thread' for this to
76218          * avoid clobber warnings.  Any valid, reachable 'thr' value would be
76219          * fine for this, so using 'entry_thread' is just to silence warnings.
76220          */
76221         thr = entry_thread->heap->curr_thread;
76222         DUK_ASSERT(thr != NULL);
76223         DUK_ASSERT(thr->callstack_top >= 1);
76224         DUK_ASSERT(thr->callstack_curr != NULL);
76225         DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack_curr) != NULL);
76226         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack_curr)));
76227
76228         DUK_GC_TORTURE(thr->heap);
76229
76230         thr->ptr_curr_pc = &curr_pc;
76231
76232         /* Relookup and initialize dispatch loop variables.  Debugger check. */
76233         {
76234                 duk_activation *act;
76235 #if !defined(DUK_USE_EXEC_FUN_LOCAL)
76236                 duk_hcompfunc *fun;
76237 #endif
76238
76239                 /* Assume interrupt init/counter are properly initialized here. */
76240                 /* Assume that thr->valstack_bottom has been set-up before getting here. */
76241
76242                 act = thr->callstack_curr;
76243                 DUK_ASSERT(act != NULL);
76244                 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
76245                 DUK_ASSERT(fun != NULL);
76246                 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);
76247                 consts = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, fun);
76248                 DUK_ASSERT(consts != NULL);
76249
76250 #if defined(DUK_USE_DEBUGGER_SUPPORT)
76251                 if (DUK_UNLIKELY(duk_debug_is_attached(thr->heap) && !thr->heap->dbg_processing)) {
76252                         duk__executor_recheck_debugger(thr, act, fun);
76253                         DUK_ASSERT(act == thr->callstack_curr);
76254                         DUK_ASSERT(act != NULL);
76255                 }
76256 #endif  /* DUK_USE_DEBUGGER_SUPPORT */
76257
76258 #if defined(DUK_USE_ASSERTIONS)
76259                 valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack);
76260 #endif
76261
76262                 /* Set up curr_pc for opcode dispatch. */
76263                 curr_pc = act->curr_pc;
76264         }
76265
76266         DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p,"
76267                            "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, "
76268                            "preventcount=%ld",
76269                            (void *) thr,
76270                            (long) (thr->callstack_top - 1),
76271                            (void *) DUK__FUN(),
76272                            (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, DUK__FUN()),
76273                            (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, DUK__FUN()),
76274                            (long) (thr->callstack_top - 1),
76275                            (long) (thr->valstack_bottom - thr->valstack),
76276                            (long) (thr->valstack_top - thr->valstack),
76277                            (long) thr->callstack_preventcount));
76278
76279         /* Dispatch loop. */
76280
76281         for (;;) {
76282                 duk_uint8_t op;
76283
76284                 DUK_ASSERT(thr->callstack_top >= 1);
76285                 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs);
76286                 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base);
76287
76288                 /* Executor interrupt counter check, used to implement breakpoints,
76289                  * debugging interface, execution timeouts, etc.  The counter is heap
76290                  * specific but is maintained in the current thread to make the check
76291                  * as fast as possible.  The counter is copied back to the heap struct
76292                  * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro.
76293                  */
76294 #if defined(DUK_USE_INTERRUPT_COUNTER)
76295                 int_ctr = thr->interrupt_counter;
76296                 if (DUK_LIKELY(int_ctr > 0)) {
76297                         thr->interrupt_counter = int_ctr - 1;
76298                 } else {
76299                         /* Trigger at zero or below */
76300                         duk_small_uint_t exec_int_ret;
76301
76302                         DUK_STATS_INC(thr->heap, stats_exec_interrupt);
76303
76304                         /* Write curr_pc back for the debugger. */
76305                         {
76306                                 duk_activation *act;
76307                                 DUK_ASSERT(thr->callstack_top > 0);
76308                                 act = thr->callstack_curr;
76309                                 DUK_ASSERT(act != NULL);
76310                                 act->curr_pc = (duk_instr_t *) curr_pc;
76311                         }
76312
76313                         /* Forced restart caused by a function return; must recheck
76314                          * debugger breakpoints before checking line transitions,
76315                          * see GH-303.  Restart and then handle interrupt_counter
76316                          * zero again.
76317                          */
76318 #if defined(DUK_USE_DEBUGGER_SUPPORT)
76319                         if (thr->heap->dbg_force_restart) {
76320                                 DUK_DD(DUK_DDPRINT("dbg_force_restart flag forced restart execution"));  /* GH-303 */
76321                                 thr->heap->dbg_force_restart = 0;
76322                                 goto restart_execution;
76323                         }
76324 #endif
76325
76326                         exec_int_ret = duk__executor_interrupt(thr);
76327                         if (exec_int_ret == DUK__INT_RESTART) {
76328                                 /* curr_pc synced back above */
76329                                 goto restart_execution;
76330                         }
76331                 }
76332 #endif  /* DUK_USE_INTERRUPT_COUNTER */
76333 #if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
76334                 /* For cross-checking during development: ensure dispatch count
76335                  * matches cumulative interrupt counter init value sums.
76336                  */
76337                 thr->heap->inst_count_exec++;
76338 #endif
76339
76340 #if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG)
76341                 {
76342                         duk_activation *act;
76343                         act = thr->callstack_curr;
76344                         DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN()));
76345                         DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN()));
76346                         DUK_UNREF(act);  /* if debugging disabled */
76347
76348                         DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld  -->  %!I",
76349                                              (long) (curr_pc - DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())),
76350                                              (unsigned long) *curr_pc,
76351                                              (long) DUK_DEC_OP(*curr_pc),
76352                                              (long) (thr->valstack_top - thr->valstack),
76353                                              (long) (thr->valstack_end - thr->valstack),
76354                                              (long) (DUK__FUN() ? DUK__FUN()->nregs : -1),
76355                                              (duk_instr_t) *curr_pc));
76356                 }
76357 #endif
76358
76359 #if defined(DUK_USE_ASSERTIONS)
76360                 /* Quite heavy assert: check valstack policy.  Improper
76361                  * shuffle instructions can write beyond valstack_top/end
76362                  * so this check catches them in the act.
76363                  */
76364                 {
76365                         duk_tval *tv;
76366                         tv = thr->valstack_top;
76367                         while (tv != thr->valstack_end) {
76368                                 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
76369                                 tv++;
76370                         }
76371                 }
76372 #endif
76373
76374                 ins = *curr_pc++;
76375                 DUK_STATS_INC(thr->heap, stats_exec_opcodes);
76376
76377                 /* Typing: use duk_small_(u)int_fast_t when decoding small
76378                  * opcode fields (op, A, B, C, BC) which fit into 16 bits
76379                  * and duk_(u)int_fast_t when decoding larger fields (e.g.
76380                  * ABC).  Use unsigned variant by default, signed when the
76381                  * value is used in signed arithmetic.  Using variable names
76382                  * such as 'a', 'b', 'c', 'bc', etc makes it easier to spot
76383                  * typing mismatches.
76384                  */
76385
76386                 /* Switch based on opcode.  Cast to 8-bit unsigned value and
76387                  * use a fully populated case clauses so that the compiler
76388                  * will (at least usually) omit a bounds check.
76389                  */
76390                 op = (duk_uint8_t) DUK_DEC_OP(ins);
76391                 switch (op) {
76392
76393                 /* Some useful macros.  These access inner executor variables
76394                  * directly so they only apply within the executor.
76395                  */
76396 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76397 #define DUK__REPLACE_TOP_A_BREAK() { goto replace_top_a; }
76398 #define DUK__REPLACE_TOP_BC_BREAK() { goto replace_top_bc; }
76399 #define DUK__REPLACE_BOOL_A_BREAK(bval) { \
76400                 duk_bool_t duk__bval; \
76401                 duk__bval = (bval); \
76402                 DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
76403                 duk_push_boolean(thr, duk__bval); \
76404                 DUK__REPLACE_TOP_A_BREAK(); \
76405         }
76406 #else
76407 #define DUK__REPLACE_TOP_A_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins)); break; }
76408 #define DUK__REPLACE_TOP_BC_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins)); break; }
76409 #define DUK__REPLACE_BOOL_A_BREAK(bval) { \
76410                 duk_bool_t duk__bval; \
76411                 duk_tval *duk__tvdst; \
76412                 duk__bval = (bval); \
76413                 DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
76414                 duk__tvdst = DUK__REGP_A(ins); \
76415                 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, duk__tvdst, duk__bval); \
76416                 break; \
76417         }
76418 #endif
76419
76420                 /* XXX: 12 + 12 bit variant might make sense too, for both reg and
76421                  * const loads.
76422                  */
76423
76424                 /* For LDREG, STREG, LDCONST footprint optimized variants would just
76425                  * duk_dup() + duk_replace(), but because they're used quite a lot
76426                  * they're currently intentionally not size optimized.
76427                  */
76428                 case DUK_OP_LDREG: {
76429                         duk_tval *tv1, *tv2;
76430
76431                         tv1 = DUK__REGP_A(ins);
76432                         tv2 = DUK__REGP_BC(ins);
76433                         DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2);  /* side effects */
76434                         break;
76435                 }
76436
76437                 case DUK_OP_STREG: {
76438                         duk_tval *tv1, *tv2;
76439
76440                         tv1 = DUK__REGP_A(ins);
76441                         tv2 = DUK__REGP_BC(ins);
76442                         DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1);  /* side effects */
76443                         break;
76444                 }
76445
76446                 case DUK_OP_LDCONST: {
76447                         duk_tval *tv1, *tv2;
76448
76449                         tv1 = DUK__REGP_A(ins);
76450                         tv2 = DUK__CONSTP_BC(ins);
76451                         DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2);  /* side effects */
76452                         break;
76453                 }
76454
76455                 /* LDINT and LDINTX are intended to load an arbitrary signed
76456                  * 32-bit value.  Only an LDINT+LDINTX sequence is supported.
76457                  * This also guarantees all values remain fastints.
76458                  */
76459 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76460                 case DUK_OP_LDINT: {
76461                         duk_int32_t val;
76462
76463                         val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
76464                         duk_push_int(thr, val);
76465                         DUK__REPLACE_TOP_A_BREAK();
76466                 }
76467                 case DUK_OP_LDINTX: {
76468                         duk_int32_t val;
76469
76470                         val = (duk_int32_t) duk_get_int(thr, DUK_DEC_A(ins));
76471                         val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins);  /* no bias */
76472                         duk_push_int(thr, val);
76473                         DUK__REPLACE_TOP_A_BREAK();
76474                 }
76475 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76476                 case DUK_OP_LDINT: {
76477                         duk_tval *tv1;
76478                         duk_int32_t val;
76479
76480                         val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
76481                         tv1 = DUK__REGP_A(ins);
76482                         DUK_TVAL_SET_I32_UPDREF(thr, tv1, val);  /* side effects */
76483                         break;
76484                 }
76485                 case DUK_OP_LDINTX: {
76486                         duk_tval *tv1;
76487                         duk_int32_t val;
76488
76489                         tv1 = DUK__REGP_A(ins);
76490                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
76491 #if defined(DUK_USE_FASTINT)
76492                         DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
76493                         val = DUK_TVAL_GET_FASTINT_I32(tv1);
76494 #else
76495                         /* XXX: fast double-to-int conversion, we know number is integer in [-0x80000000,0xffffffff]. */
76496                         val = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv1);
76497 #endif
76498                         val = (duk_int32_t) ((duk_uint32_t) val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins);  /* no bias */
76499                         DUK_TVAL_SET_I32_UPDREF(thr, tv1, val);  /* side effects */
76500                         break;
76501                 }
76502 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76503
76504 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76505                 case DUK_OP_LDTHIS: {
76506                         duk_push_this(thr);
76507                         DUK__REPLACE_TOP_BC_BREAK();
76508                 }
76509                 case DUK_OP_LDUNDEF: {
76510                         duk_to_undefined(thr, (duk_idx_t) DUK_DEC_BC(ins));
76511                         break;
76512                 }
76513                 case DUK_OP_LDNULL: {
76514                         duk_to_null(thr, (duk_idx_t) DUK_DEC_BC(ins));
76515                         break;
76516                 }
76517                 case DUK_OP_LDTRUE: {
76518                         duk_push_true(thr);
76519                         DUK__REPLACE_TOP_BC_BREAK();
76520                 }
76521                 case DUK_OP_LDFALSE: {
76522                         duk_push_false(thr);
76523                         DUK__REPLACE_TOP_BC_BREAK();
76524                 }
76525 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76526                 case DUK_OP_LDTHIS: {
76527                         /* Note: 'this' may be bound to any value, not just an object */
76528                         duk_tval *tv1, *tv2;
76529
76530                         tv1 = DUK__REGP_BC(ins);
76531                         tv2 = thr->valstack_bottom - 1;  /* 'this binding' is just under bottom */
76532                         DUK_ASSERT(tv2 >= thr->valstack);
76533                         DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2);  /* side effects */
76534                         break;
76535                 }
76536                 case DUK_OP_LDUNDEF: {
76537                         duk_tval *tv1;
76538
76539                         tv1 = DUK__REGP_BC(ins);
76540                         DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1);  /* side effects */
76541                         break;
76542                 }
76543                 case DUK_OP_LDNULL: {
76544                         duk_tval *tv1;
76545
76546                         tv1 = DUK__REGP_BC(ins);
76547                         DUK_TVAL_SET_NULL_UPDREF(thr, tv1);  /* side effects */
76548                         break;
76549                 }
76550                 case DUK_OP_LDTRUE: {
76551                         duk_tval *tv1;
76552
76553                         tv1 = DUK__REGP_BC(ins);
76554                         DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 1);  /* side effects */
76555                         break;
76556                 }
76557                 case DUK_OP_LDFALSE: {
76558                         duk_tval *tv1;
76559
76560                         tv1 = DUK__REGP_BC(ins);
76561                         DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 0);  /* side effects */
76562                         break;
76563                 }
76564 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76565
76566                 case DUK_OP_BNOT: {
76567                         duk__vm_bitwise_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins));
76568                         break;
76569                 }
76570
76571                 case DUK_OP_LNOT: {
76572                         duk__vm_logical_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins));
76573                         break;
76574                 }
76575
76576 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76577                 case DUK_OP_UNM:
76578                 case DUK_OP_UNP: {
76579                         duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), op);
76580                         break;
76581                 }
76582 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76583                 case DUK_OP_UNM: {
76584                         duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNM);
76585                         break;
76586                 }
76587                 case DUK_OP_UNP: {
76588                         duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNP);
76589                         break;
76590                 }
76591 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76592
76593 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76594                 case DUK_OP_TYPEOF: {
76595                         duk_small_uint_t stridx;
76596
76597                         stridx = duk_js_typeof_stridx(DUK__REGP_BC(ins));
76598                         DUK_ASSERT_STRIDX_VALID(stridx);
76599                         duk_push_hstring_stridx(thr, stridx);
76600                         DUK__REPLACE_TOP_A_BREAK();
76601                 }
76602 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76603                 case DUK_OP_TYPEOF: {
76604                         duk_tval *tv;
76605                         duk_small_uint_t stridx;
76606                         duk_hstring *h_str;
76607
76608                         tv = DUK__REGP_BC(ins);
76609                         stridx = duk_js_typeof_stridx(tv);
76610                         DUK_ASSERT_STRIDX_VALID(stridx);
76611                         h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
76612                         tv = DUK__REGP_A(ins);
76613                         DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str);
76614                         break;
76615                 }
76616 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76617
76618                 case DUK_OP_TYPEOFID: {
76619                         duk_small_uint_t stridx;
76620 #if !defined(DUK_USE_EXEC_PREFER_SIZE)
76621                         duk_hstring *h_str;
76622 #endif
76623                         duk_activation *act;
76624                         duk_hstring *name;
76625                         duk_tval *tv;
76626
76627                         /* A -> target register
76628                          * BC -> constant index of identifier name
76629                          */
76630
76631                         tv = DUK__CONSTP_BC(ins);
76632                         DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
76633                         name = DUK_TVAL_GET_STRING(tv);
76634                         tv = NULL;  /* lookup has side effects */
76635                         act = thr->callstack_curr;
76636                         if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
76637                                 /* -> [... val this] */
76638                                 tv = DUK_GET_TVAL_NEGIDX(thr, -2);
76639                                 stridx = duk_js_typeof_stridx(tv);
76640                                 tv = NULL;  /* no longer needed */
76641                                 duk_pop_2_unsafe(thr);
76642                         } else {
76643                                 /* unresolvable, no stack changes */
76644                                 stridx = DUK_STRIDX_LC_UNDEFINED;
76645                         }
76646                         DUK_ASSERT_STRIDX_VALID(stridx);
76647 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76648                         duk_push_hstring_stridx(thr, stridx);
76649                         DUK__REPLACE_TOP_A_BREAK();
76650 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76651                         h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
76652                         tv = DUK__REGP_A(ins);
76653                         DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str);
76654                         break;
76655 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76656                 }
76657
76658                 /* Equality: E5 Sections 11.9.1, 11.9.3 */
76659
76660 #define DUK__EQ_BODY(barg,carg) { \
76661                 duk_bool_t tmp; \
76662                 tmp = duk_js_equals(thr, (barg), (carg)); \
76663                 DUK_ASSERT(tmp == 0 || tmp == 1); \
76664                 DUK__REPLACE_BOOL_A_BREAK(tmp); \
76665         }
76666 #define DUK__NEQ_BODY(barg,carg) { \
76667                 duk_bool_t tmp; \
76668                 tmp = duk_js_equals(thr, (barg), (carg)); \
76669                 DUK_ASSERT(tmp == 0 || tmp == 1); \
76670                 tmp ^= 1; \
76671                 DUK__REPLACE_BOOL_A_BREAK(tmp); \
76672         }
76673 #define DUK__SEQ_BODY(barg,carg) { \
76674                 duk_bool_t tmp; \
76675                 tmp = duk_js_strict_equals((barg), (carg)); \
76676                 DUK_ASSERT(tmp == 0 || tmp == 1); \
76677                 DUK__REPLACE_BOOL_A_BREAK(tmp); \
76678         }
76679 #define DUK__SNEQ_BODY(barg,carg) { \
76680                 duk_bool_t tmp; \
76681                 tmp = duk_js_strict_equals((barg), (carg)); \
76682                 DUK_ASSERT(tmp == 0 || tmp == 1); \
76683                 tmp ^= 1; \
76684                 DUK__REPLACE_BOOL_A_BREAK(tmp); \
76685         }
76686 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76687                 case DUK_OP_EQ_RR:
76688                 case DUK_OP_EQ_CR:
76689                 case DUK_OP_EQ_RC:
76690                 case DUK_OP_EQ_CC:
76691                         DUK__EQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
76692                 case DUK_OP_NEQ_RR:
76693                 case DUK_OP_NEQ_CR:
76694                 case DUK_OP_NEQ_RC:
76695                 case DUK_OP_NEQ_CC:
76696                         DUK__NEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
76697                 case DUK_OP_SEQ_RR:
76698                 case DUK_OP_SEQ_CR:
76699                 case DUK_OP_SEQ_RC:
76700                 case DUK_OP_SEQ_CC:
76701                         DUK__SEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
76702                 case DUK_OP_SNEQ_RR:
76703                 case DUK_OP_SNEQ_CR:
76704                 case DUK_OP_SNEQ_RC:
76705                 case DUK_OP_SNEQ_CC:
76706                         DUK__SNEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
76707 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76708                 case DUK_OP_EQ_RR:
76709                         DUK__EQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
76710                 case DUK_OP_EQ_CR:
76711                         DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
76712                 case DUK_OP_EQ_RC:
76713                         DUK__EQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
76714                 case DUK_OP_EQ_CC:
76715                         DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
76716                 case DUK_OP_NEQ_RR:
76717                         DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
76718                 case DUK_OP_NEQ_CR:
76719                         DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
76720                 case DUK_OP_NEQ_RC:
76721                         DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
76722                 case DUK_OP_NEQ_CC:
76723                         DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
76724                 case DUK_OP_SEQ_RR:
76725                         DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
76726                 case DUK_OP_SEQ_CR:
76727                         DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
76728                 case DUK_OP_SEQ_RC:
76729                         DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
76730                 case DUK_OP_SEQ_CC:
76731                         DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
76732                 case DUK_OP_SNEQ_RR:
76733                         DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
76734                 case DUK_OP_SNEQ_CR:
76735                         DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
76736                 case DUK_OP_SNEQ_RC:
76737                         DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
76738                 case DUK_OP_SNEQ_CC:
76739                         DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
76740 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76741
76742 #define DUK__COMPARE_BODY(arg1,arg2,flags) { \
76743                 duk_bool_t tmp; \
76744                 tmp = duk_js_compare_helper(thr, (arg1), (arg2), (flags)); \
76745                 DUK_ASSERT(tmp == 0 || tmp == 1); \
76746                 DUK__REPLACE_BOOL_A_BREAK(tmp); \
76747         }
76748 #define DUK__GT_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), 0)
76749 #define DUK__GE_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
76750 #define DUK__LT_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
76751 #define DUK__LE_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), DUK_COMPARE_FLAG_NEGATE)
76752 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76753                 case DUK_OP_GT_RR:
76754                 case DUK_OP_GT_CR:
76755                 case DUK_OP_GT_RC:
76756                 case DUK_OP_GT_CC:
76757                         DUK__GT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
76758                 case DUK_OP_GE_RR:
76759                 case DUK_OP_GE_CR:
76760                 case DUK_OP_GE_RC:
76761                 case DUK_OP_GE_CC:
76762                         DUK__GE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
76763                 case DUK_OP_LT_RR:
76764                 case DUK_OP_LT_CR:
76765                 case DUK_OP_LT_RC:
76766                 case DUK_OP_LT_CC:
76767                         DUK__LT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
76768                 case DUK_OP_LE_RR:
76769                 case DUK_OP_LE_CR:
76770                 case DUK_OP_LE_RC:
76771                 case DUK_OP_LE_CC:
76772                         DUK__LE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
76773 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76774                 case DUK_OP_GT_RR:
76775                         DUK__GT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
76776                 case DUK_OP_GT_CR:
76777                         DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
76778                 case DUK_OP_GT_RC:
76779                         DUK__GT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
76780                 case DUK_OP_GT_CC:
76781                         DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
76782                 case DUK_OP_GE_RR:
76783                         DUK__GE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
76784                 case DUK_OP_GE_CR:
76785                         DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
76786                 case DUK_OP_GE_RC:
76787                         DUK__GE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
76788                 case DUK_OP_GE_CC:
76789                         DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
76790                 case DUK_OP_LT_RR:
76791                         DUK__LT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
76792                 case DUK_OP_LT_CR:
76793                         DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
76794                 case DUK_OP_LT_RC:
76795                         DUK__LT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
76796                 case DUK_OP_LT_CC:
76797                         DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
76798                 case DUK_OP_LE_RR:
76799                         DUK__LE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
76800                 case DUK_OP_LE_CR:
76801                         DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
76802                 case DUK_OP_LE_RC:
76803                         DUK__LE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
76804                 case DUK_OP_LE_CC:
76805                         DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
76806 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76807
76808                 /* No size optimized variant at present for IF. */
76809                 case DUK_OP_IFTRUE_R: {
76810                         if (duk_js_toboolean(DUK__REGP_BC(ins)) != 0) {
76811                                 curr_pc++;
76812                         }
76813                         break;
76814                 }
76815                 case DUK_OP_IFTRUE_C: {
76816                         if (duk_js_toboolean(DUK__CONSTP_BC(ins)) != 0) {
76817                                 curr_pc++;
76818                         }
76819                         break;
76820                 }
76821                 case DUK_OP_IFFALSE_R: {
76822                         if (duk_js_toboolean(DUK__REGP_BC(ins)) == 0) {
76823                                 curr_pc++;
76824                         }
76825                         break;
76826                 }
76827                 case DUK_OP_IFFALSE_C: {
76828                         if (duk_js_toboolean(DUK__CONSTP_BC(ins)) == 0) {
76829                                 curr_pc++;
76830                         }
76831                         break;
76832                 }
76833
76834 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76835                 case DUK_OP_ADD_RR:
76836                 case DUK_OP_ADD_CR:
76837                 case DUK_OP_ADD_RC:
76838                 case DUK_OP_ADD_CC: {
76839                         /* XXX: could leave value on stack top and goto replace_top_a; */
76840                         duk__vm_arith_add(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins));
76841                         break;
76842                 }
76843 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76844                 case DUK_OP_ADD_RR: {
76845                         duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins));
76846                         break;
76847                 }
76848                 case DUK_OP_ADD_CR: {
76849                         duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins));
76850                         break;
76851                 }
76852                 case DUK_OP_ADD_RC: {
76853                         duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins));
76854                         break;
76855                 }
76856                 case DUK_OP_ADD_CC: {
76857                         duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins));
76858                         break;
76859                 }
76860 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76861
76862 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76863                 case DUK_OP_SUB_RR:
76864                 case DUK_OP_SUB_CR:
76865                 case DUK_OP_SUB_RC:
76866                 case DUK_OP_SUB_CC:
76867                 case DUK_OP_MUL_RR:
76868                 case DUK_OP_MUL_CR:
76869                 case DUK_OP_MUL_RC:
76870                 case DUK_OP_MUL_CC:
76871                 case DUK_OP_DIV_RR:
76872                 case DUK_OP_DIV_CR:
76873                 case DUK_OP_DIV_RC:
76874                 case DUK_OP_DIV_CC:
76875                 case DUK_OP_MOD_RR:
76876                 case DUK_OP_MOD_CR:
76877                 case DUK_OP_MOD_RC:
76878                 case DUK_OP_MOD_CC:
76879 #if defined(DUK_USE_ES7_EXP_OPERATOR)
76880                 case DUK_OP_EXP_RR:
76881                 case DUK_OP_EXP_CR:
76882                 case DUK_OP_EXP_RC:
76883                 case DUK_OP_EXP_CC:
76884 #endif  /* DUK_USE_ES7_EXP_OPERATOR */
76885                 {
76886                         /* XXX: could leave value on stack top and goto replace_top_a; */
76887                         duk__vm_arith_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op);
76888                         break;
76889                 }
76890 #else  /* DUK_USE_EXEC_PREFER_SIZE */
76891                 case DUK_OP_SUB_RR: {
76892                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
76893                         break;
76894                 }
76895                 case DUK_OP_SUB_CR: {
76896                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
76897                         break;
76898                 }
76899                 case DUK_OP_SUB_RC: {
76900                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
76901                         break;
76902                 }
76903                 case DUK_OP_SUB_CC: {
76904                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
76905                         break;
76906                 }
76907                 case DUK_OP_MUL_RR: {
76908                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
76909                         break;
76910                 }
76911                 case DUK_OP_MUL_CR: {
76912                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
76913                         break;
76914                 }
76915                 case DUK_OP_MUL_RC: {
76916                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
76917                         break;
76918                 }
76919                 case DUK_OP_MUL_CC: {
76920                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
76921                         break;
76922                 }
76923                 case DUK_OP_DIV_RR: {
76924                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
76925                         break;
76926                 }
76927                 case DUK_OP_DIV_CR: {
76928                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
76929                         break;
76930                 }
76931                 case DUK_OP_DIV_RC: {
76932                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
76933                         break;
76934                 }
76935                 case DUK_OP_DIV_CC: {
76936                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
76937                         break;
76938                 }
76939                 case DUK_OP_MOD_RR: {
76940                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
76941                         break;
76942                 }
76943                 case DUK_OP_MOD_CR: {
76944                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
76945                         break;
76946                 }
76947                 case DUK_OP_MOD_RC: {
76948                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
76949                         break;
76950                 }
76951                 case DUK_OP_MOD_CC: {
76952                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
76953                         break;
76954                 }
76955 #if defined(DUK_USE_ES7_EXP_OPERATOR)
76956                 case DUK_OP_EXP_RR: {
76957                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
76958                         break;
76959                 }
76960                 case DUK_OP_EXP_CR: {
76961                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
76962                         break;
76963                 }
76964                 case DUK_OP_EXP_RC: {
76965                         duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
76966                         break;
76967                 }
76968                 case DUK_OP_EXP_CC: {
76969                         duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
76970                         break;
76971                 }
76972 #endif  /* DUK_USE_ES7_EXP_OPERATOR */
76973 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
76974
76975 #if defined(DUK_USE_EXEC_PREFER_SIZE)
76976                 case DUK_OP_BAND_RR:
76977                 case DUK_OP_BAND_CR:
76978                 case DUK_OP_BAND_RC:
76979                 case DUK_OP_BAND_CC:
76980                 case DUK_OP_BOR_RR:
76981                 case DUK_OP_BOR_CR:
76982                 case DUK_OP_BOR_RC:
76983                 case DUK_OP_BOR_CC:
76984                 case DUK_OP_BXOR_RR:
76985                 case DUK_OP_BXOR_CR:
76986                 case DUK_OP_BXOR_RC:
76987                 case DUK_OP_BXOR_CC:
76988                 case DUK_OP_BASL_RR:
76989                 case DUK_OP_BASL_CR:
76990                 case DUK_OP_BASL_RC:
76991                 case DUK_OP_BASL_CC:
76992                 case DUK_OP_BLSR_RR:
76993                 case DUK_OP_BLSR_CR:
76994                 case DUK_OP_BLSR_RC:
76995                 case DUK_OP_BLSR_CC:
76996                 case DUK_OP_BASR_RR:
76997                 case DUK_OP_BASR_CR:
76998                 case DUK_OP_BASR_RC:
76999                 case DUK_OP_BASR_CC: {
77000                         /* XXX: could leave value on stack top and goto replace_top_a; */
77001                         duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op);
77002                         break;
77003                 }
77004 #else  /* DUK_USE_EXEC_PREFER_SIZE */
77005                 case DUK_OP_BAND_RR: {
77006                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
77007                         break;
77008                 }
77009                 case DUK_OP_BAND_CR: {
77010                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
77011                         break;
77012                 }
77013                 case DUK_OP_BAND_RC: {
77014                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
77015                         break;
77016                 }
77017                 case DUK_OP_BAND_CC: {
77018                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
77019                         break;
77020                 }
77021                 case DUK_OP_BOR_RR: {
77022                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
77023                         break;
77024                 }
77025                 case DUK_OP_BOR_CR: {
77026                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
77027                         break;
77028                 }
77029                 case DUK_OP_BOR_RC: {
77030                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
77031                         break;
77032                 }
77033                 case DUK_OP_BOR_CC: {
77034                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
77035                         break;
77036                 }
77037                 case DUK_OP_BXOR_RR: {
77038                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
77039                         break;
77040                 }
77041                 case DUK_OP_BXOR_CR: {
77042                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
77043                         break;
77044                 }
77045                 case DUK_OP_BXOR_RC: {
77046                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
77047                         break;
77048                 }
77049                 case DUK_OP_BXOR_CC: {
77050                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
77051                         break;
77052                 }
77053                 case DUK_OP_BASL_RR: {
77054                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
77055                         break;
77056                 }
77057                 case DUK_OP_BASL_CR: {
77058                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
77059                         break;
77060                 }
77061                 case DUK_OP_BASL_RC: {
77062                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
77063                         break;
77064                 }
77065                 case DUK_OP_BASL_CC: {
77066                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
77067                         break;
77068                 }
77069                 case DUK_OP_BLSR_RR: {
77070                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
77071                         break;
77072                 }
77073                 case DUK_OP_BLSR_CR: {
77074                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
77075                         break;
77076                 }
77077                 case DUK_OP_BLSR_RC: {
77078                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
77079                         break;
77080                 }
77081                 case DUK_OP_BLSR_CC: {
77082                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
77083                         break;
77084                 }
77085                 case DUK_OP_BASR_RR: {
77086                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
77087                         break;
77088                 }
77089                 case DUK_OP_BASR_CR: {
77090                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
77091                         break;
77092                 }
77093                 case DUK_OP_BASR_RC: {
77094                         duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
77095                         break;
77096                 }
77097                 case DUK_OP_BASR_CC: {
77098                         duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
77099                         break;
77100                 }
77101 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
77102
77103                 /* For INSTOF and IN, B is always a register. */
77104 #define DUK__INSTOF_BODY(barg,carg) { \
77105                 duk_bool_t tmp; \
77106                 tmp = duk_js_instanceof(thr, (barg), (carg)); \
77107                 DUK_ASSERT(tmp == 0 || tmp == 1); \
77108                 DUK__REPLACE_BOOL_A_BREAK(tmp); \
77109         }
77110 #define DUK__IN_BODY(barg,carg) { \
77111                 duk_bool_t tmp; \
77112                 tmp = duk_js_in(thr, (barg), (carg)); \
77113                 DUK_ASSERT(tmp == 0 || tmp == 1); \
77114                 DUK__REPLACE_BOOL_A_BREAK(tmp); \
77115         }
77116 #if defined(DUK_USE_EXEC_PREFER_SIZE)
77117                 case DUK_OP_INSTOF_RR:
77118                 case DUK_OP_INSTOF_CR:
77119                 case DUK_OP_INSTOF_RC:
77120                 case DUK_OP_INSTOF_CC:
77121                         DUK__INSTOF_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
77122                 case DUK_OP_IN_RR:
77123                 case DUK_OP_IN_CR:
77124                 case DUK_OP_IN_RC:
77125                 case DUK_OP_IN_CC:
77126                         DUK__IN_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
77127 #else  /* DUK_USE_EXEC_PREFER_SIZE */
77128                 case DUK_OP_INSTOF_RR:
77129                         DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
77130                 case DUK_OP_INSTOF_CR:
77131                         DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
77132                 case DUK_OP_INSTOF_RC:
77133                         DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
77134                 case DUK_OP_INSTOF_CC:
77135                         DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
77136                 case DUK_OP_IN_RR:
77137                         DUK__IN_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
77138                 case DUK_OP_IN_CR:
77139                         DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
77140                 case DUK_OP_IN_RC:
77141                         DUK__IN_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
77142                 case DUK_OP_IN_CC:
77143                         DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
77144 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
77145
77146                 /* Pre/post inc/dec for register variables, important for loops. */
77147 #if defined(DUK_USE_EXEC_PREFER_SIZE)
77148                 case DUK_OP_PREINCR:
77149                 case DUK_OP_PREDECR:
77150                 case DUK_OP_POSTINCR:
77151                 case DUK_OP_POSTDECR: {
77152                         duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), op);
77153                         break;
77154                 }
77155                 case DUK_OP_PREINCV:
77156                 case DUK_OP_PREDECV:
77157                 case DUK_OP_POSTINCV:
77158                 case DUK_OP_POSTDECV: {
77159                         duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), op, DUK__STRICT());
77160                         break;
77161                 }
77162 #else  /* DUK_USE_EXEC_PREFER_SIZE */
77163                 case DUK_OP_PREINCR: {
77164                         duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREINCR);
77165                         break;
77166                 }
77167                 case DUK_OP_PREDECR: {
77168                         duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREDECR);
77169                         break;
77170                 }
77171                 case DUK_OP_POSTINCR: {
77172                         duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTINCR);
77173                         break;
77174                 }
77175                 case DUK_OP_POSTDECR: {
77176                         duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTDECR);
77177                         break;
77178                 }
77179                 case DUK_OP_PREINCV: {
77180                         duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREINCV, DUK__STRICT());
77181                         break;
77182                 }
77183                 case DUK_OP_PREDECV: {
77184                         duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREDECV, DUK__STRICT());
77185                         break;
77186                 }
77187                 case DUK_OP_POSTINCV: {
77188                         duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTINCV, DUK__STRICT());
77189                         break;
77190                 }
77191                 case DUK_OP_POSTDECV: {
77192                         duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTDECV, DUK__STRICT());
77193                         break;
77194                 }
77195 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
77196
77197                 /* XXX: Move to separate helper, optimize for perf/size separately. */
77198                 /* Preinc/predec for object properties. */
77199                 case DUK_OP_PREINCP_RR:
77200                 case DUK_OP_PREINCP_CR:
77201                 case DUK_OP_PREINCP_RC:
77202                 case DUK_OP_PREINCP_CC:
77203                 case DUK_OP_PREDECP_RR:
77204                 case DUK_OP_PREDECP_CR:
77205                 case DUK_OP_PREDECP_RC:
77206                 case DUK_OP_PREDECP_CC:
77207                 case DUK_OP_POSTINCP_RR:
77208                 case DUK_OP_POSTINCP_CR:
77209                 case DUK_OP_POSTINCP_RC:
77210                 case DUK_OP_POSTINCP_CC:
77211                 case DUK_OP_POSTDECP_RR:
77212                 case DUK_OP_POSTDECP_CR:
77213                 case DUK_OP_POSTDECP_RC:
77214                 case DUK_OP_POSTDECP_CC: {
77215                         duk_tval *tv_obj;
77216                         duk_tval *tv_key;
77217                         duk_tval *tv_val;
77218                         duk_bool_t rc;
77219                         duk_double_t x, y, z;
77220 #if !defined(DUK_USE_EXEC_PREFER_SIZE)
77221                         duk_tval *tv_dst;
77222 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
77223
77224                         /* A -> target reg
77225                          * B -> object reg/const (may be const e.g. in "'foo'[1]")
77226                          * C -> key reg/const
77227                          */
77228
77229                         /* Opcode bits 0-1 are used to distinguish reg/const variants.
77230                          * Opcode bits 2-3 are used to distinguish inc/dec variants:
77231                          * Bit 2 = inc(0)/dec(1), bit 3 = pre(0)/post(1).
77232                          */
77233                         DUK_ASSERT((DUK_OP_PREINCP_RR & 0x0c) == 0x00);
77234                         DUK_ASSERT((DUK_OP_PREDECP_RR & 0x0c) == 0x04);
77235                         DUK_ASSERT((DUK_OP_POSTINCP_RR & 0x0c) == 0x08);
77236                         DUK_ASSERT((DUK_OP_POSTDECP_RR & 0x0c) == 0x0c);
77237
77238                         tv_obj = DUK__REGCONSTP_B(ins);
77239                         tv_key = DUK__REGCONSTP_C(ins);
77240                         rc = duk_hobject_getprop(thr, tv_obj, tv_key);  /* -> [val] */
77241                         DUK_UNREF(rc);  /* ignore */
77242                         tv_obj = NULL;  /* invalidated */
77243                         tv_key = NULL;  /* invalidated */
77244
77245                         /* XXX: Fastint fast path would be useful here.  Also fastints
77246                          * now lose their fastint status in current handling which is
77247                          * not intuitive.
77248                          */
77249
77250                         x = duk_to_number_m1(thr);
77251                         duk_pop_unsafe(thr);
77252                         if (ins & DUK_BC_INCDECP_FLAG_DEC) {
77253                                 y = x - 1.0;
77254                         } else {
77255                                 y = x + 1.0;
77256                         }
77257
77258                         duk_push_number(thr, y);
77259                         tv_val = DUK_GET_TVAL_NEGIDX(thr, -1);
77260                         DUK_ASSERT(tv_val != NULL);
77261                         tv_obj = DUK__REGCONSTP_B(ins);
77262                         tv_key = DUK__REGCONSTP_C(ins);
77263                         rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
77264                         DUK_UNREF(rc);  /* ignore */
77265                         tv_obj = NULL;  /* invalidated */
77266                         tv_key = NULL;  /* invalidated */
77267                         duk_pop_unsafe(thr);
77268
77269                         z = (ins & DUK_BC_INCDECP_FLAG_POST) ? x : y;
77270 #if defined(DUK_USE_EXEC_PREFER_SIZE)
77271                         duk_push_number(thr, z);
77272                         DUK__REPLACE_TOP_A_BREAK();
77273 #else
77274                         tv_dst = DUK__REGP_A(ins);
77275                         DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z);
77276                         break;
77277 #endif
77278                 }
77279
77280                 /* XXX: GETPROP where object is 'this', GETPROPT?
77281                  * Occurs relatively often in object oriented code.
77282                  */
77283
77284 #define DUK__GETPROP_BODY(barg,carg) { \
77285                 /* A -> target reg \
77286                  * B -> object reg/const (may be const e.g. in "'foo'[1]") \
77287                  * C -> key reg/const \
77288                  */ \
77289                 (void) duk_hobject_getprop(thr, (barg), (carg)); \
77290                 DUK__REPLACE_TOP_A_BREAK(); \
77291         }
77292 #define DUK__GETPROPC_BODY(barg,carg) { \
77293                 /* Same as GETPROP but callability check for property-based calls. */ \
77294                 duk_tval *tv__targ; \
77295                 (void) duk_hobject_getprop(thr, (barg), (carg)); \
77296                 DUK_GC_TORTURE(thr->heap); \
77297                 tv__targ = DUK_GET_TVAL_NEGIDX(thr, -1); \
77298                 if (DUK_UNLIKELY(!duk_is_callable_tval(thr, tv__targ))) { \
77299                         /* Here we intentionally re-evaluate the macro \
77300                          * arguments to deal with potentially changed \
77301                          * valstack base pointer! \
77302                          */ \
77303                         duk_call_setup_propcall_error(thr, tv__targ, (barg), (carg)); \
77304                 } \
77305                 DUK__REPLACE_TOP_A_BREAK(); \
77306         }
77307 #define DUK__PUTPROP_BODY(aarg,barg,carg) { \
77308                 /* A -> object reg \
77309                  * B -> key reg/const \
77310                  * C -> value reg/const \
77311                  * \
77312                  * Note: intentional difference to register arrangement \
77313                  * of e.g. GETPROP; 'A' must contain a register-only value. \
77314                  */ \
77315                 (void) duk_hobject_putprop(thr, (aarg), (barg), (carg), DUK__STRICT()); \
77316                 break; \
77317         }
77318 #define DUK__DELPROP_BODY(barg,carg) { \
77319                 /* A -> result reg \
77320                  * B -> object reg \
77321                  * C -> key reg/const \
77322                  */ \
77323                 duk_bool_t rc; \
77324                 rc = duk_hobject_delprop(thr, (barg), (carg), DUK__STRICT()); \
77325                 DUK_ASSERT(rc == 0 || rc == 1); \
77326                 DUK__REPLACE_BOOL_A_BREAK(rc); \
77327         }
77328 #if defined(DUK_USE_EXEC_PREFER_SIZE)
77329                 case DUK_OP_GETPROP_RR:
77330                 case DUK_OP_GETPROP_CR:
77331                 case DUK_OP_GETPROP_RC:
77332                 case DUK_OP_GETPROP_CC:
77333                         DUK__GETPROP_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
77334 #if defined(DUK_USE_VERBOSE_ERRORS)
77335                 case DUK_OP_GETPROPC_RR:
77336                 case DUK_OP_GETPROPC_CR:
77337                 case DUK_OP_GETPROPC_RC:
77338                 case DUK_OP_GETPROPC_CC:
77339                         DUK__GETPROPC_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
77340 #endif
77341                 case DUK_OP_PUTPROP_RR:
77342                 case DUK_OP_PUTPROP_CR:
77343                 case DUK_OP_PUTPROP_RC:
77344                 case DUK_OP_PUTPROP_CC:
77345                         DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
77346                 case DUK_OP_DELPROP_RR:
77347                 case DUK_OP_DELPROP_RC:  /* B is always reg */
77348                         DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGCONSTP_C(ins));
77349 #else  /* DUK_USE_EXEC_PREFER_SIZE */
77350                 case DUK_OP_GETPROP_RR:
77351                         DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
77352                 case DUK_OP_GETPROP_CR:
77353                         DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
77354                 case DUK_OP_GETPROP_RC:
77355                         DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
77356                 case DUK_OP_GETPROP_CC:
77357                         DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
77358 #if defined(DUK_USE_VERBOSE_ERRORS)
77359                 case DUK_OP_GETPROPC_RR:
77360                         DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
77361                 case DUK_OP_GETPROPC_CR:
77362                         DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
77363                 case DUK_OP_GETPROPC_RC:
77364                         DUK__GETPROPC_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
77365                 case DUK_OP_GETPROPC_CC:
77366                         DUK__GETPROPC_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
77367 #endif
77368                 case DUK_OP_PUTPROP_RR:
77369                         DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__REGP_C(ins));
77370                 case DUK_OP_PUTPROP_CR:
77371                         DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__REGP_C(ins));
77372                 case DUK_OP_PUTPROP_RC:
77373                         DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__CONSTP_C(ins));
77374                 case DUK_OP_PUTPROP_CC:
77375                         DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
77376                 case DUK_OP_DELPROP_RR:  /* B is always reg */
77377                         DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
77378                 case DUK_OP_DELPROP_RC:
77379                         DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
77380 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
77381
77382                 /* No fast path for DECLVAR now, it's quite a rare instruction. */
77383                 case DUK_OP_DECLVAR_RR:
77384                 case DUK_OP_DECLVAR_CR:
77385                 case DUK_OP_DECLVAR_RC:
77386                 case DUK_OP_DECLVAR_CC: {
77387                         duk_activation *act;
77388                         duk_small_uint_fast_t a = DUK_DEC_A(ins);
77389                         duk_tval *tv1;
77390                         duk_hstring *name;
77391                         duk_small_uint_t prop_flags;
77392                         duk_bool_t is_func_decl;
77393
77394                         tv1 = DUK__REGCONSTP_B(ins);
77395                         DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
77396                         name = DUK_TVAL_GET_STRING(tv1);
77397                         DUK_ASSERT(name != NULL);
77398
77399                         is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0);
77400
77401                         /* XXX: declvar takes an duk_tval pointer, which is awkward and
77402                          * should be reworked.
77403                          */
77404
77405                         /* Compiler is responsible for selecting property flags (configurability,
77406                          * writability, etc).
77407                          */
77408                         prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
77409
77410                         if (is_func_decl) {
77411                                 duk_push_tval(thr, DUK__REGCONSTP_C(ins));
77412                         } else {
77413                                 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));  /* valstack policy */
77414                                 thr->valstack_top++;
77415                         }
77416                         tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
77417
77418                         act = thr->callstack_curr;
77419                         if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
77420                                 if (is_func_decl) {
77421                                         /* Already declared, update value. */
77422                                         tv1 = DUK_GET_TVAL_NEGIDX(thr, -1);
77423                                         duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
77424                                 } else {
77425                                         /* Already declared but no initializer value
77426                                          * (e.g. 'var xyz;'), no-op.
77427                                          */
77428                                 }
77429                         }
77430
77431                         duk_pop_unsafe(thr);
77432                         break;
77433                 }
77434
77435 #if defined(DUK_USE_REGEXP_SUPPORT)
77436                 /* The compiler should never emit DUK_OP_REGEXP if there is no
77437                  * regexp support.
77438                  */
77439                 case DUK_OP_REGEXP_RR:
77440                 case DUK_OP_REGEXP_CR:
77441                 case DUK_OP_REGEXP_RC:
77442                 case DUK_OP_REGEXP_CC: {
77443                         /* A -> target register
77444                          * B -> bytecode (also contains flags)
77445                          * C -> escaped source
77446                          */
77447
77448                         duk_push_tval(thr, DUK__REGCONSTP_C(ins));
77449                         duk_push_tval(thr, DUK__REGCONSTP_B(ins));  /* -> [ ... escaped_source bytecode ] */
77450                         duk_regexp_create_instance(thr);   /* -> [ ... regexp_instance ] */
77451                         DUK__REPLACE_TOP_A_BREAK();
77452                 }
77453 #endif  /* DUK_USE_REGEXP_SUPPORT */
77454
77455                 /* XXX: 'c' is unused, use whole BC, etc. */
77456                 case DUK_OP_CSVAR_RR:
77457                 case DUK_OP_CSVAR_CR:
77458                 case DUK_OP_CSVAR_RC:
77459                 case DUK_OP_CSVAR_CC: {
77460                         /* The speciality of calling through a variable binding is that the
77461                          * 'this' value may be provided by the variable lookup: E5 Section 6.b.i.
77462                          *
77463                          * The only (standard) case where the 'this' binding is non-null is when
77464                          *   (1) the variable is found in an object environment record, and
77465                          *   (2) that object environment record is a 'with' block.
77466                          */
77467
77468                         duk_activation *act;
77469                         duk_uint_fast_t idx;
77470                         duk_tval *tv1;
77471                         duk_hstring *name;
77472
77473                         /* A -> target registers (A, A + 1) for call setup
77474                          * B -> identifier name, usually constant but can be a register due to shuffling
77475                          */
77476
77477                         tv1 = DUK__REGCONSTP_B(ins);
77478                         DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
77479                         name = DUK_TVAL_GET_STRING(tv1);
77480                         DUK_ASSERT(name != NULL);
77481                         act = thr->callstack_curr;
77482                         (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/);  /* -> [... val this] */
77483
77484                         idx = (duk_uint_fast_t) DUK_DEC_A(ins);
77485
77486                         /* Could add direct value stack handling. */
77487                         duk_replace(thr, (duk_idx_t) (idx + 1));  /* 'this' binding */
77488                         duk_replace(thr, (duk_idx_t) idx);        /* variable value (function, we hope, not checked here) */
77489                         break;
77490                 }
77491
77492                 case DUK_OP_CLOSURE: {
77493                         duk_activation *act;
77494                         duk_hcompfunc *fun_act;
77495                         duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
77496                         duk_hobject *fun_temp;
77497
77498                         /* A -> target reg
77499                          * BC -> inner function index
77500                          */
77501
77502                         DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)",
77503                                              (long) DUK_DEC_A(ins), (long) DUK_DEC_BC(ins), (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())));
77504
77505                         DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */
77506                         DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN()));
77507
77508                         act = thr->callstack_curr;
77509                         fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
77510                         fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc];
77511                         DUK_ASSERT(fun_temp != NULL);
77512                         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(fun_temp));
77513
77514                         DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O",
77515                                              (void *) fun_temp, (duk_heaphdr *) fun_temp));
77516
77517                         if (act->lex_env == NULL) {
77518                                 DUK_ASSERT(act->var_env == NULL);
77519                                 duk_js_init_activation_environment_records_delayed(thr, act);
77520                                 act = thr->callstack_curr;
77521                         }
77522                         DUK_ASSERT(act->lex_env != NULL);
77523                         DUK_ASSERT(act->var_env != NULL);
77524
77525                         /* functions always have a NEWENV flag, i.e. they get a
77526                          * new variable declaration environment, so only lex_env
77527                          * matters here.
77528                          */
77529                         duk_js_push_closure(thr,
77530                                             (duk_hcompfunc *) fun_temp,
77531                                             act->var_env,
77532                                             act->lex_env,
77533                                             1 /*add_auto_proto*/);
77534                         DUK__REPLACE_TOP_A_BREAK();
77535                 }
77536
77537                 case DUK_OP_GETVAR: {
77538                         duk_activation *act;
77539                         duk_tval *tv1;
77540                         duk_hstring *name;
77541
77542                         tv1 = DUK__CONSTP_BC(ins);
77543                         DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
77544                         name = DUK_TVAL_GET_STRING(tv1);
77545                         DUK_ASSERT(name != NULL);
77546                         act = thr->callstack_curr;
77547                         DUK_ASSERT(act != NULL);
77548                         (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/);  /* -> [... val this] */
77549                         duk_pop_unsafe(thr);  /* 'this' binding is not needed here */
77550                         DUK__REPLACE_TOP_A_BREAK();
77551                 }
77552
77553                 case DUK_OP_PUTVAR: {
77554                         duk_activation *act;
77555                         duk_tval *tv1;
77556                         duk_hstring *name;
77557
77558                         tv1 = DUK__CONSTP_BC(ins);
77559                         DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
77560                         name = DUK_TVAL_GET_STRING(tv1);
77561                         DUK_ASSERT(name != NULL);
77562
77563                         /* XXX: putvar takes a duk_tval pointer, which is awkward and
77564                          * should be reworked.
77565                          */
77566
77567                         tv1 = DUK__REGP_A(ins);  /* val */
77568                         act = thr->callstack_curr;
77569                         duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
77570                         break;
77571                 }
77572
77573                 case DUK_OP_DELVAR: {
77574                         duk_activation *act;
77575                         duk_tval *tv1;
77576                         duk_hstring *name;
77577                         duk_bool_t rc;
77578
77579                         tv1 = DUK__CONSTP_BC(ins);
77580                         DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
77581                         name = DUK_TVAL_GET_STRING(tv1);
77582                         DUK_ASSERT(name != NULL);
77583                         act = thr->callstack_curr;
77584                         rc = duk_js_delvar_activation(thr, act, name);
77585                         DUK__REPLACE_BOOL_A_BREAK(rc);
77586                 }
77587
77588                 case DUK_OP_JUMP: {
77589                         /* Note: without explicit cast to signed, MSVC will
77590                          * apparently generate a large positive jump when the
77591                          * bias-corrected value would normally be negative.
77592                          */
77593                         curr_pc += (duk_int_fast_t) DUK_DEC_ABC(ins) - (duk_int_fast_t) DUK_BC_JUMP_BIAS;
77594                         break;
77595                 }
77596
77597 #define DUK__RETURN_SHARED() do { \
77598                 duk_small_uint_t ret_result; \
77599                 /* duk__handle_return() is guaranteed never to throw, except \
77600                  * for potential out-of-memory situations which will then \
77601                  * propagate out of the executor longjmp handler. \
77602                  */ \
77603                 DUK_ASSERT(thr->ptr_curr_pc == NULL); \
77604                 ret_result = duk__handle_return(thr, entry_act); \
77605                 if (ret_result == DUK__RETHAND_RESTART) { \
77606                         goto restart_execution; \
77607                 } \
77608                 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED); \
77609                 return; \
77610         } while (0)
77611 #if defined(DUK_USE_EXEC_PREFER_SIZE)
77612                 case DUK_OP_RETREG:
77613                 case DUK_OP_RETCONST:
77614                 case DUK_OP_RETCONSTN:
77615                 case DUK_OP_RETUNDEF: {
77616                          /* BC -> return value reg/const */
77617
77618                         DUK__SYNC_AND_NULL_CURR_PC();
77619
77620                         if (op == DUK_OP_RETREG) {
77621                                 duk_push_tval(thr, DUK__REGP_BC(ins));
77622                         } else if (op == DUK_OP_RETUNDEF) {
77623                                 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));  /* valstack policy */
77624                                 thr->valstack_top++;
77625                         } else {
77626                                 DUK_ASSERT(op == DUK_OP_RETCONST || op == DUK_OP_RETCONSTN);
77627                                 duk_push_tval(thr, DUK__CONSTP_BC(ins));
77628                         }
77629
77630                         DUK__RETURN_SHARED();
77631                 }
77632 #else  /* DUK_USE_EXEC_PREFER_SIZE */
77633                 case DUK_OP_RETREG: {
77634                         duk_tval *tv;
77635
77636                         DUK__SYNC_AND_NULL_CURR_PC();
77637                         tv = DUK__REGP_BC(ins);
77638                         DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
77639                         DUK_TVAL_INCREF(thr, tv);
77640                         thr->valstack_top++;
77641                         DUK__RETURN_SHARED();
77642                 }
77643                 /* This will be unused without refcounting. */
77644                 case DUK_OP_RETCONST: {
77645                         duk_tval *tv;
77646
77647                         DUK__SYNC_AND_NULL_CURR_PC();
77648                         tv = DUK__CONSTP_BC(ins);
77649                         DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
77650                         DUK_TVAL_INCREF(thr, tv);
77651                         thr->valstack_top++;
77652                         DUK__RETURN_SHARED();
77653                 }
77654                 case DUK_OP_RETCONSTN: {
77655                         duk_tval *tv;
77656
77657                         DUK__SYNC_AND_NULL_CURR_PC();
77658                         tv = DUK__CONSTP_BC(ins);
77659                         DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
77660 #if defined(DUK_USE_REFERENCE_COUNTING)
77661                         /* Without refcounting only RETCONSTN is used. */
77662                         DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv));  /* no INCREF for this constant */
77663 #endif
77664                         thr->valstack_top++;
77665                         DUK__RETURN_SHARED();
77666                 }
77667                 case DUK_OP_RETUNDEF: {
77668                         DUK__SYNC_AND_NULL_CURR_PC();
77669                         thr->valstack_top++;  /* value at valstack top is already undefined by valstack policy */
77670                         DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
77671                         DUK__RETURN_SHARED();
77672                 }
77673 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
77674
77675                 case DUK_OP_LABEL: {
77676                         duk_activation *act;
77677                         duk_catcher *cat;
77678                         duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
77679
77680                         /* Allocate catcher and populate it (must be atomic). */
77681
77682                         cat = duk_hthread_catcher_alloc(thr);
77683                         DUK_ASSERT(cat != NULL);
77684
77685                         cat->flags = (duk_uint32_t) (DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT));
77686                         cat->pc_base = (duk_instr_t *) curr_pc;  /* pre-incremented, points to first jump slot */
77687                         cat->idx_base = 0;  /* unused for label */
77688                         cat->h_varname = NULL;
77689
77690                         act = thr->callstack_curr;
77691                         DUK_ASSERT(act != NULL);
77692                         cat->parent = act->cat;
77693                         act->cat = cat;
77694
77695                         DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, pc_base=%ld, "
77696                                              "idx_base=%ld, h_varname=%!O, label_id=%ld",
77697                                              (long) cat->flags, (long) cat->pc_base,
77698                                              (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
77699
77700                         curr_pc += 2;  /* skip jump slots */
77701                         break;
77702                 }
77703
77704                 case DUK_OP_ENDLABEL: {
77705                         duk_activation *act;
77706 #if (defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)) || defined(DUK_USE_ASSERTIONS)
77707                         duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
77708 #endif
77709 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
77710                         DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
77711 #endif
77712
77713                         act = thr->callstack_curr;
77714                         DUK_ASSERT(act->cat != NULL);
77715                         DUK_ASSERT(DUK_CAT_GET_TYPE(act->cat) == DUK_CAT_TYPE_LABEL);
77716                         DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(act->cat) == bc);
77717                         duk_hthread_catcher_unwind_nolexenv_norz(thr, act);
77718
77719                         /* no need to unwind callstack */
77720                         break;
77721                 }
77722
77723                 case DUK_OP_BREAK: {
77724                         duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
77725
77726                         DUK__SYNC_AND_NULL_CURR_PC();
77727                         duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK);
77728                         goto restart_execution;
77729                 }
77730
77731                 case DUK_OP_CONTINUE: {
77732                         duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
77733
77734                         DUK__SYNC_AND_NULL_CURR_PC();
77735                         duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE);
77736                         goto restart_execution;
77737                 }
77738
77739                 /* XXX: move to helper, too large to be inline here */
77740                 case DUK_OP_TRYCATCH: {
77741                         duk__handle_op_trycatch(thr, ins, curr_pc);
77742                         curr_pc += 2;  /* skip jump slots */
77743                         break;
77744                 }
77745
77746                 case DUK_OP_ENDTRY: {
77747                         curr_pc = duk__handle_op_endtry(thr, ins);
77748                         break;
77749                 }
77750
77751                 case DUK_OP_ENDCATCH: {
77752                         duk__handle_op_endcatch(thr, ins);
77753                         break;
77754                 }
77755
77756                 case DUK_OP_ENDFIN: {
77757                         /* Sync and NULL early. */
77758                         DUK__SYNC_AND_NULL_CURR_PC();
77759
77760                         if (duk__handle_op_endfin(thr, ins, entry_act) != 0) {
77761                                 return;
77762                         }
77763
77764                         /* Must restart because we NULLed out curr_pc. */
77765                         goto restart_execution;
77766                 }
77767
77768                 case DUK_OP_THROW: {
77769                         duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
77770
77771                         /* Note: errors are augmented when they are created, not
77772                          * when they are thrown.  So, don't augment here, it would
77773                          * break re-throwing for instance.
77774                          */
77775
77776                         /* Sync so that augmentation sees up-to-date activations, NULL
77777                          * thr->ptr_curr_pc so that it's not used if side effects occur
77778                          * in augmentation or longjmp handling.
77779                          */
77780                         DUK__SYNC_AND_NULL_CURR_PC();
77781
77782                         duk_dup(thr, (duk_idx_t) bc);
77783                         DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
77784                                              (duk_tval *) duk_get_tval(thr, -1)));
77785 #if defined(DUK_USE_AUGMENT_ERROR_THROW)
77786                         duk_err_augment_error_throw(thr);
77787                         DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
77788                                              (duk_tval *) duk_get_tval(thr, -1)));
77789 #endif
77790
77791                         duk_err_setup_ljstate1(thr, DUK_LJ_TYPE_THROW, DUK_GET_TVAL_NEGIDX(thr, -1));
77792 #if defined(DUK_USE_DEBUGGER_SUPPORT)
77793                         duk_err_check_debugger_integration(thr);
77794 #endif
77795
77796                         DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL);  /* always in executor */
77797                         duk_err_longjmp(thr);
77798                         DUK_UNREACHABLE();
77799                         break;
77800                 }
77801
77802                 case DUK_OP_CSREG: {
77803                         /*
77804                          *  Assuming a register binds to a variable declared within this
77805                          *  function (a declarative binding), the 'this' for the call
77806                          *  setup is always 'undefined'.  E5 Section 10.2.1.1.6.
77807                          */
77808
77809                         duk_small_uint_fast_t a = DUK_DEC_A(ins);
77810                         duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
77811
77812                         /* A -> register containing target function (not type checked here)
77813                          * BC -> target registers (BC, BC + 1) for call setup
77814                          */
77815
77816 #if defined(DUK_USE_PREFER_SIZE)
77817                         duk_dup(thr, (duk_idx_t) a);
77818                         duk_replace(thr, (duk_idx_t) bc);
77819                         duk_to_undefined(thr, (duk_idx_t) (bc + 1));
77820 #else
77821                         duk_tval *tv1;
77822                         duk_tval *tv2;
77823                         duk_tval *tv3;
77824                         duk_tval tv_tmp1;
77825                         duk_tval tv_tmp2;
77826
77827                         tv1 = DUK__REGP(bc);
77828                         tv2 = tv1 + 1;
77829                         DUK_TVAL_SET_TVAL(&tv_tmp1, tv1);
77830                         DUK_TVAL_SET_TVAL(&tv_tmp2, tv2);
77831                         tv3 = DUK__REGP(a);
77832                         DUK_TVAL_SET_TVAL(tv1, tv3);
77833                         DUK_TVAL_INCREF(thr, tv1);  /* no side effects */
77834                         DUK_TVAL_SET_UNDEFINED(tv2);  /* no need for incref */
77835                         DUK_TVAL_DECREF(thr, &tv_tmp1);
77836                         DUK_TVAL_DECREF(thr, &tv_tmp2);
77837 #endif
77838                         break;
77839                 }
77840
77841
77842                 /* XXX: in some cases it's faster NOT to reuse the value
77843                  * stack but rather copy the arguments on top of the stack
77844                  * (mainly when the calling value stack is large and the value
77845                  * stack resize would be large).
77846                  */
77847
77848                 case DUK_OP_CALL0:
77849                 case DUK_OP_CALL1:
77850                 case DUK_OP_CALL2:
77851                 case DUK_OP_CALL3:
77852                 case DUK_OP_CALL4:
77853                 case DUK_OP_CALL5:
77854                 case DUK_OP_CALL6:
77855                 case DUK_OP_CALL7: {
77856                         /* Opcode packs 4 flag bits: 1 for indirect, 3 map
77857                          * 1:1 to three lowest call handling flags.
77858                          *
77859                          * A -> nargs or register with nargs (indirect)
77860                          * BC -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
77861                          */
77862
77863                         duk_idx_t nargs;
77864                         duk_idx_t idx;
77865                         duk_small_uint_t call_flags;
77866 #if !defined(DUK_USE_EXEC_FUN_LOCAL)
77867                         duk_hcompfunc *fun;
77868 #endif
77869
77870                         DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0);
77871                         DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) == 0);
77872
77873                         nargs = (duk_idx_t) DUK_DEC_A(ins);
77874                         call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA;
77875                         idx = (duk_idx_t) DUK_DEC_BC(ins);
77876
77877                         if (duk__executor_handle_call(thr, idx, nargs, call_flags)) {
77878                                 /* curr_pc synced by duk_handle_call_unprotected() */
77879                                 DUK_ASSERT(thr->ptr_curr_pc == NULL);
77880                                 goto restart_execution;
77881                         }
77882                         DUK_ASSERT(thr->ptr_curr_pc != NULL);
77883
77884                         /* duk_js_call.c is required to restore the stack reserve
77885                          * so we only need to reset the top.
77886                          */
77887 #if !defined(DUK_USE_EXEC_FUN_LOCAL)
77888                         fun = DUK__FUN();
77889 #endif
77890                         duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs);
77891
77892                         /* No need to reinit setjmp() catchpoint, as call handling
77893                          * will store and restore our state.
77894                          *
77895                          * When debugger is enabled, we need to recheck the activation
77896                          * status after returning.  This is now handled by call handling
77897                          * and heap->dbg_force_restart.
77898                          */
77899                         break;
77900                 }
77901
77902                 case DUK_OP_CALL8:
77903                 case DUK_OP_CALL9:
77904                 case DUK_OP_CALL10:
77905                 case DUK_OP_CALL11:
77906                 case DUK_OP_CALL12:
77907                 case DUK_OP_CALL13:
77908                 case DUK_OP_CALL14:
77909                 case DUK_OP_CALL15: {
77910                         /* Indirect variant. */
77911                         duk_uint_fast_t nargs;
77912                         duk_idx_t idx;
77913                         duk_small_uint_t call_flags;
77914 #if !defined(DUK_USE_EXEC_FUN_LOCAL)
77915                         duk_hcompfunc *fun;
77916 #endif
77917
77918                         DUK_ASSERT((DUK_OP_CALL0 & 0x0fU) == 0);
77919                         DUK_ASSERT((ins & DUK_BC_CALL_FLAG_INDIRECT) != 0);
77920
77921                         nargs = (duk_uint_fast_t) DUK_DEC_A(ins);
77922                         DUK__LOOKUP_INDIRECT(nargs);
77923                         call_flags = (ins & 0x07U) | DUK_CALL_FLAG_ALLOW_ECMATOECMA;
77924                         idx = (duk_idx_t) DUK_DEC_BC(ins);
77925
77926                         if (duk__executor_handle_call(thr, idx, (duk_idx_t) nargs, call_flags)) {
77927                                 DUK_ASSERT(thr->ptr_curr_pc == NULL);
77928                                 goto restart_execution;
77929                         }
77930                         DUK_ASSERT(thr->ptr_curr_pc != NULL);
77931
77932 #if !defined(DUK_USE_EXEC_FUN_LOCAL)
77933                         fun = DUK__FUN();
77934 #endif
77935                         duk_set_top_unsafe(thr, (duk_idx_t) fun->nregs);
77936                         break;
77937                 }
77938
77939                 case DUK_OP_NEWOBJ: {
77940                         duk_push_object(thr);
77941 #if defined(DUK_USE_ASSERTIONS)
77942                         {
77943                                 duk_hobject *h;
77944                                 h = duk_require_hobject(thr, -1);
77945                                 DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0);
77946                                 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0);
77947                                 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0);
77948                                 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0);
77949                         }
77950 #endif
77951 #if !defined(DUK_USE_PREFER_SIZE)
77952                         /* XXX: could do a direct props realloc, but need hash size */
77953                         duk_hobject_resize_entrypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins));
77954 #endif
77955                         DUK__REPLACE_TOP_BC_BREAK();
77956                 }
77957
77958                 case DUK_OP_NEWARR: {
77959                         duk_push_array(thr);
77960 #if defined(DUK_USE_ASSERTIONS)
77961                         {
77962                                 duk_hobject *h;
77963                                 h = duk_require_hobject(thr, -1);
77964                                 DUK_ASSERT(DUK_HOBJECT_GET_ESIZE(h) == 0);
77965                                 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h) == 0);
77966                                 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0);
77967                                 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(h) == 0);
77968                                 DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(h));
77969                         }
77970 #endif
77971 #if !defined(DUK_USE_PREFER_SIZE)
77972                         duk_hobject_realloc_props(thr,
77973                                                   duk_known_hobject(thr, -1),
77974                                                   0 /*new_e_size*/,
77975                                                   DUK_DEC_A(ins) /*new_a_size*/,
77976                                                   0 /*new_h_size*/,
77977                                                   0 /*abandon_array*/);
77978 #if 0
77979                         duk_hobject_resize_arraypart(thr, duk_known_hobject(thr, -1), DUK_DEC_A(ins));
77980 #endif
77981 #endif
77982                         DUK__REPLACE_TOP_BC_BREAK();
77983                 }
77984
77985                 case DUK_OP_MPUTOBJ:
77986                 case DUK_OP_MPUTOBJI: {
77987                         duk_idx_t obj_idx;
77988                         duk_uint_fast_t idx, idx_end;
77989                         duk_small_uint_fast_t count;
77990
77991                         /* A -> register of target object
77992                          * B -> first register of key/value pair list
77993                          *      or register containing first register number if indirect
77994                          * C -> number of key/value pairs * 2
77995                          *      (= number of value stack indices used starting from 'B')
77996                          */
77997
77998                         obj_idx = DUK_DEC_A(ins);
77999                         DUK_ASSERT(duk_is_object(thr, obj_idx));
78000
78001                         idx = (duk_uint_fast_t) DUK_DEC_B(ins);
78002                         if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
78003                                 DUK__LOOKUP_INDIRECT(idx);
78004                         }
78005
78006                         count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
78007                         DUK_ASSERT(count > 0);  /* compiler guarantees */
78008                         idx_end = idx + count;
78009
78010 #if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
78011                         if (DUK_UNLIKELY(idx_end > (duk_uint_fast_t) duk_get_top(thr))) {
78012                                 /* XXX: use duk_is_valid_index() instead? */
78013                                 /* XXX: improve check; check against nregs, not against top */
78014                                 DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
78015                         }
78016 #endif
78017
78018                         /* Use 'force' flag to duk_def_prop() to ensure that any
78019                          * inherited properties don't prevent the operation.
78020                          * With ES2015 duplicate properties are allowed, so that we
78021                          * must overwrite any previous data or accessor property.
78022                          *
78023                          * With ES2015 computed property names the literal keys
78024                          * may be arbitrary values and need to be ToPropertyKey()
78025                          * coerced at runtime.
78026                          */
78027                         do {
78028                                 /* XXX: faster initialization (direct access or better primitives) */
78029                                 duk_dup(thr, (duk_idx_t) idx);
78030                                 duk_dup(thr, (duk_idx_t) (idx + 1));
78031                                 duk_def_prop(thr, obj_idx, DUK_DEFPROP_HAVE_VALUE |
78032                                                            DUK_DEFPROP_FORCE |
78033                                                            DUK_DEFPROP_SET_WRITABLE |
78034                                                            DUK_DEFPROP_SET_ENUMERABLE |
78035                                                            DUK_DEFPROP_SET_CONFIGURABLE);
78036                                 idx += 2;
78037                         } while (idx < idx_end);
78038                         break;
78039                 }
78040
78041                 case DUK_OP_INITSET:
78042                 case DUK_OP_INITGET: {
78043                         duk__handle_op_initset_initget(thr, ins);
78044                         break;
78045                 }
78046
78047                 case DUK_OP_MPUTARR:
78048                 case DUK_OP_MPUTARRI: {
78049                         duk_idx_t obj_idx;
78050                         duk_uint_fast_t idx, idx_end;
78051                         duk_small_uint_fast_t count;
78052                         duk_tval *tv1;
78053                         duk_uint32_t arr_idx;
78054
78055                         /* A -> register of target object
78056                          * B -> first register of value data (start_index, value1, value2, ..., valueN)
78057                          *      or register containing first register number if indirect
78058                          * C -> number of key/value pairs (N)
78059                          */
78060
78061                         obj_idx = DUK_DEC_A(ins);
78062                         DUK_ASSERT(duk_is_object(thr, obj_idx));
78063
78064                         idx = (duk_uint_fast_t) DUK_DEC_B(ins);
78065                         if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
78066                                 DUK__LOOKUP_INDIRECT(idx);
78067                         }
78068
78069                         count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
78070                         DUK_ASSERT(count > 0 + 1);  /* compiler guarantees */
78071                         idx_end = idx + count;
78072
78073 #if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
78074                         if (idx_end > (duk_uint_fast_t) duk_get_top(thr)) {
78075                                 /* XXX: use duk_is_valid_index() instead? */
78076                                 /* XXX: improve check; check against nregs, not against top */
78077                                 DUK__INTERNAL_ERROR("MPUTARR out of bounds");
78078                         }
78079 #endif
78080
78081                         tv1 = DUK__REGP(idx);
78082                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
78083 #if defined(DUK_USE_FASTINT)
78084                         DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
78085                         arr_idx = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1);
78086 #else
78087                         arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
78088 #endif
78089                         idx++;
78090
78091                         do {
78092                                 /* duk_xdef_prop() will define an own property without any array
78093                                  * special behaviors.  We'll need to set the array length explicitly
78094                                  * in the end.  For arrays with elisions, the compiler will emit an
78095                                  * explicit SETALEN which will update the length.
78096                                  */
78097
78098                                 /* XXX: because we're dealing with 'own' properties of a fresh array,
78099                                  * the array initializer should just ensure that the array has a large
78100                                  * enough array part and write the values directly into array part,
78101                                  * and finally set 'length' manually in the end (as already happens now).
78102                                  */
78103
78104                                 duk_dup(thr, (duk_idx_t) idx);
78105                                 duk_xdef_prop_index_wec(thr, obj_idx, arr_idx);
78106
78107                                 idx++;
78108                                 arr_idx++;
78109                         } while (idx < idx_end);
78110
78111                         /* XXX: E5.1 Section 11.1.4 coerces the final length through
78112                          * ToUint32() which is odd but happens now as a side effect of
78113                          * 'arr_idx' type.
78114                          */
78115                         duk_set_length(thr, obj_idx, (duk_size_t) (duk_uarridx_t) arr_idx);
78116                         break;
78117                 }
78118
78119                 case DUK_OP_SETALEN: {
78120                         duk_tval *tv1;
78121                         duk_hobject *h;
78122                         duk_uint32_t len;
78123
78124                         tv1 = DUK__REGP_A(ins);
78125                         DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
78126                         h = DUK_TVAL_GET_OBJECT(tv1);
78127                         DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(h));
78128
78129                         tv1 = DUK__REGP_BC(ins);
78130                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
78131 #if defined(DUK_USE_FASTINT)
78132                         DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
78133                         len = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1);
78134 #else
78135                         len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
78136 #endif
78137                         ((duk_harray *) h)->length = len;
78138                         break;
78139                 }
78140
78141                 case DUK_OP_INITENUM: {
78142                         duk__handle_op_initenum(thr, ins);
78143                         break;
78144                 }
78145
78146                 case DUK_OP_NEXTENUM: {
78147                         curr_pc += duk__handle_op_nextenum(thr, ins);
78148                         break;
78149                 }
78150
78151                 case DUK_OP_INVLHS: {
78152                         DUK_ERROR_REFERENCE(thr, DUK_STR_INVALID_LVALUE);
78153                         DUK_WO_NORETURN(return;);
78154                         break;
78155                 }
78156
78157                 case DUK_OP_DEBUGGER: {
78158                         /* Opcode only emitted by compiler when debugger
78159                          * support is enabled.  Ignore it silently without
78160                          * debugger support, in case it has been loaded
78161                          * from precompiled bytecode.
78162                          */
78163 #if defined(DUK_USE_DEBUGGER_SUPPORT)
78164                         if (duk_debug_is_attached(thr->heap)) {
78165                                 DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution"));
78166                                 DUK__SYNC_AND_NULL_CURR_PC();
78167                                 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
78168                                 DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution"));
78169                                 goto restart_execution;
78170                         } else {
78171                                 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached"));
78172                         }
78173 #else
78174                         DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support"));
78175 #endif
78176                         break;
78177                 }
78178
78179                 case DUK_OP_NOP: {
78180                         /* Nop, ignored, but ABC fields may carry a value e.g.
78181                          * for indirect opcode handling.
78182                          */
78183                         break;
78184                 }
78185
78186                 case DUK_OP_INVALID: {
78187                         DUK_ERROR_FMT1(thr, DUK_ERR_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_ABC(ins));
78188                         DUK_WO_NORETURN(return;);
78189                         break;
78190                 }
78191
78192 #if defined(DUK_USE_ES6)
78193                 case DUK_OP_NEWTARGET: {
78194                         duk_push_new_target(thr);
78195                         DUK__REPLACE_TOP_BC_BREAK();
78196                 }
78197 #endif  /* DUK_USE_ES6 */
78198
78199 #if !defined(DUK_USE_EXEC_PREFER_SIZE)
78200 #if !defined(DUK_USE_ES7_EXP_OPERATOR)
78201                 case DUK_OP_EXP_RR:
78202                 case DUK_OP_EXP_CR:
78203                 case DUK_OP_EXP_RC:
78204                 case DUK_OP_EXP_CC:
78205 #endif
78206 #if !defined(DUK_USE_ES6)
78207                 case DUK_OP_NEWTARGET:
78208 #endif
78209 #if !defined(DUK_USE_VERBOSE_ERRORS)
78210                 case DUK_OP_GETPROPC_RR:
78211                 case DUK_OP_GETPROPC_CR:
78212                 case DUK_OP_GETPROPC_RC:
78213                 case DUK_OP_GETPROPC_CC:
78214 #endif
78215                 case DUK_OP_UNUSED207:
78216                 case DUK_OP_UNUSED212:
78217                 case DUK_OP_UNUSED213:
78218                 case DUK_OP_UNUSED214:
78219                 case DUK_OP_UNUSED215:
78220                 case DUK_OP_UNUSED216:
78221                 case DUK_OP_UNUSED217:
78222                 case DUK_OP_UNUSED218:
78223                 case DUK_OP_UNUSED219:
78224                 case DUK_OP_UNUSED220:
78225                 case DUK_OP_UNUSED221:
78226                 case DUK_OP_UNUSED222:
78227                 case DUK_OP_UNUSED223:
78228                 case DUK_OP_UNUSED224:
78229                 case DUK_OP_UNUSED225:
78230                 case DUK_OP_UNUSED226:
78231                 case DUK_OP_UNUSED227:
78232                 case DUK_OP_UNUSED228:
78233                 case DUK_OP_UNUSED229:
78234                 case DUK_OP_UNUSED230:
78235                 case DUK_OP_UNUSED231:
78236                 case DUK_OP_UNUSED232:
78237                 case DUK_OP_UNUSED233:
78238                 case DUK_OP_UNUSED234:
78239                 case DUK_OP_UNUSED235:
78240                 case DUK_OP_UNUSED236:
78241                 case DUK_OP_UNUSED237:
78242                 case DUK_OP_UNUSED238:
78243                 case DUK_OP_UNUSED239:
78244                 case DUK_OP_UNUSED240:
78245                 case DUK_OP_UNUSED241:
78246                 case DUK_OP_UNUSED242:
78247                 case DUK_OP_UNUSED243:
78248                 case DUK_OP_UNUSED244:
78249                 case DUK_OP_UNUSED245:
78250                 case DUK_OP_UNUSED246:
78251                 case DUK_OP_UNUSED247:
78252                 case DUK_OP_UNUSED248:
78253                 case DUK_OP_UNUSED249:
78254                 case DUK_OP_UNUSED250:
78255                 case DUK_OP_UNUSED251:
78256                 case DUK_OP_UNUSED252:
78257                 case DUK_OP_UNUSED253:
78258                 case DUK_OP_UNUSED254:
78259                 case DUK_OP_UNUSED255:
78260                 /* Force all case clauses to map to an actual handler
78261                  * so that the compiler can emit a jump without a bounds
78262                  * check: the switch argument is a duk_uint8_t so that
78263                  * the compiler may be able to figure it out.  This is
78264                  * a small detail and obviously compiler dependent.
78265                  */
78266                 /* default: clause omitted on purpose */
78267 #else  /* DUK_USE_EXEC_PREFER_SIZE */
78268                 default:
78269 #endif  /* DUK_USE_EXEC_PREFER_SIZE */
78270                 {
78271                         /* Default case catches invalid/unsupported opcodes. */
78272                         DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins));
78273                         DUK__INTERNAL_ERROR("invalid opcode");
78274                         break;
78275                 }
78276
78277                 }  /* end switch */
78278
78279                 continue;
78280
78281                 /* Some shared exit paths for opcode handling below.  These
78282                  * are mostly useful to reduce code footprint when multiple
78283                  * opcodes have a similar epilogue (like replacing stack top
78284                  * with index 'a').
78285                  */
78286
78287 #if defined(DUK_USE_EXEC_PREFER_SIZE)
78288          replace_top_a:
78289                 DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins));
78290                 continue;
78291          replace_top_bc:
78292                 DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins));
78293                 continue;
78294 #endif
78295         }
78296         DUK_WO_NORETURN(return;);
78297
78298 #if !defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS)
78299  internal_error:
78300         DUK_ERROR_INTERNAL(thr);
78301         DUK_WO_NORETURN(return;);
78302 #endif
78303 }
78304
78305 /* automatic undefs */
78306 #undef DUK__BYTEOFF_A
78307 #undef DUK__BYTEOFF_B
78308 #undef DUK__BYTEOFF_BC
78309 #undef DUK__BYTEOFF_C
78310 #undef DUK__COMPARE_BODY
78311 #undef DUK__CONST
78312 #undef DUK__CONSTP
78313 #undef DUK__CONSTP_A
78314 #undef DUK__CONSTP_B
78315 #undef DUK__CONSTP_BC
78316 #undef DUK__CONSTP_C
78317 #undef DUK__DELPROP_BODY
78318 #undef DUK__EQ_BODY
78319 #undef DUK__FUN
78320 #undef DUK__GETPROPC_BODY
78321 #undef DUK__GETPROP_BODY
78322 #undef DUK__GE_BODY
78323 #undef DUK__GT_BODY
78324 #undef DUK__INLINE_PERF
78325 #undef DUK__INSTOF_BODY
78326 #undef DUK__INTERNAL_ERROR
78327 #undef DUK__INT_NOACTION
78328 #undef DUK__INT_RESTART
78329 #undef DUK__IN_BODY
78330 #undef DUK__LE_BODY
78331 #undef DUK__LONGJMP_RESTART
78332 #undef DUK__LONGJMP_RETHROW
78333 #undef DUK__LOOKUP_INDIRECT
78334 #undef DUK__LT_BODY
78335 #undef DUK__MASK_A
78336 #undef DUK__MASK_B
78337 #undef DUK__MASK_BC
78338 #undef DUK__MASK_C
78339 #undef DUK__NEQ_BODY
78340 #undef DUK__NOINLINE_PERF
78341 #undef DUK__PUTPROP_BODY
78342 #undef DUK__RCBIT_B
78343 #undef DUK__RCBIT_C
78344 #undef DUK__REG
78345 #undef DUK__REGCONSTP_B
78346 #undef DUK__REGCONSTP_C
78347 #undef DUK__REGP
78348 #undef DUK__REGP_A
78349 #undef DUK__REGP_B
78350 #undef DUK__REGP_BC
78351 #undef DUK__REGP_C
78352 #undef DUK__REPLACE_BOOL_A_BREAK
78353 #undef DUK__REPLACE_TOP_A_BREAK
78354 #undef DUK__REPLACE_TOP_BC_BREAK
78355 #undef DUK__REPLACE_TO_TVPTR
78356 #undef DUK__RETHAND_FINISHED
78357 #undef DUK__RETHAND_RESTART
78358 #undef DUK__RETURN_SHARED
78359 #undef DUK__SEQ_BODY
78360 #undef DUK__SHIFT_A
78361 #undef DUK__SHIFT_B
78362 #undef DUK__SHIFT_BC
78363 #undef DUK__SHIFT_C
78364 #undef DUK__SNEQ_BODY
78365 #undef DUK__STRICT
78366 #undef DUK__SYNC_AND_NULL_CURR_PC
78367 #undef DUK__SYNC_CURR_PC
78368 #undef DUK__TVAL_SHIFT
78369 #line 1 "duk_js_ops.c"
78370 /*
78371  *  ECMAScript specification algorithm and conversion helpers.
78372  *
78373  *  These helpers encapsulate the primitive ECMAScript operation semantics,
78374  *  and are used by the bytecode executor and the API (among other places).
78375  *  Some primitives are only implemented as part of the API and have no
78376  *  "internal" helper.  This is the case when an internal helper would not
78377  *  really be useful; e.g. the operation is rare, uses value stack heavily,
78378  *  etc.
78379  *
78380  *  The operation arguments depend on what is required to implement
78381  *  the operation:
78382  *
78383  *    - If an operation is simple and stateless, and has no side
78384  *      effects, it won't take an duk_hthread argument and its
78385  *      arguments may be duk_tval pointers (which are safe as long
78386  *      as no side effects take place).
78387  *
78388  *    - If complex coercions are required (e.g. a "ToNumber" coercion)
78389  *      or errors may be thrown, the operation takes an duk_hthread
78390  *      argument.  This also implies that the operation may have
78391  *      arbitrary side effects, invalidating any duk_tval pointers.
78392  *
78393  *    - For operations with potential side effects, arguments can be
78394  *      taken in several ways:
78395  *
78396  *      a) as duk_tval pointers, which makes sense if the "common case"
78397  *         can be resolved without side effects (e.g. coercion); the
78398  *         arguments are pushed to the valstack for coercion if
78399  *         necessary
78400  *
78401  *      b) as duk_tval values
78402  *
78403  *      c) implicitly on value stack top
78404  *
78405  *      d) as indices to the value stack
78406  *
78407  *  Future work:
78408  *
78409  *     - Argument styles may not be the most sensible in every case now.
78410  *
78411  *     - In-place coercions might be useful for several operations, if
78412  *       in-place coercion is OK for the bytecode executor and the API.
78413  */
78414
78415 /* #include duk_internal.h -> already included */
78416
78417 /*
78418  *  ToPrimitive()  (E5 Section 9.1)
78419  *
78420  *  ==> implemented in the API.
78421  */
78422
78423 /*
78424  *  ToBoolean()  (E5 Section 9.2)
78425  */
78426
78427 DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
78428         switch (DUK_TVAL_GET_TAG(tv)) {
78429         case DUK_TAG_UNDEFINED:
78430         case DUK_TAG_NULL:
78431                 return 0;
78432         case DUK_TAG_BOOLEAN:
78433                 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 || DUK_TVAL_GET_BOOLEAN(tv) == 1);
78434                 return DUK_TVAL_GET_BOOLEAN(tv);
78435         case DUK_TAG_STRING: {
78436                 /* Symbols ToBoolean() coerce to true, regardless of their
78437                  * description.  This happens with no explicit check because
78438                  * of the symbol representation byte prefix.
78439                  */
78440                 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
78441                 DUK_ASSERT(h != NULL);
78442                 return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
78443         }
78444         case DUK_TAG_OBJECT: {
78445                 return 1;
78446         }
78447         case DUK_TAG_BUFFER: {
78448                 /* Mimic Uint8Array semantics: objects coerce true, regardless
78449                  * of buffer length (zero or not) or context.
78450                  */
78451                 return 1;
78452         }
78453         case DUK_TAG_POINTER: {
78454                 void *p = DUK_TVAL_GET_POINTER(tv);
78455                 return (p != NULL ? 1 : 0);
78456         }
78457         case DUK_TAG_LIGHTFUNC: {
78458                 return 1;
78459         }
78460 #if defined(DUK_USE_FASTINT)
78461         case DUK_TAG_FASTINT:
78462                 if (DUK_TVAL_GET_FASTINT(tv) != 0) {
78463                         return 1;
78464                 } else {
78465                         return 0;
78466                 }
78467 #endif
78468         default: {
78469                 /* number */
78470                 duk_double_t d;
78471 #if defined(DUK_USE_PREFER_SIZE)
78472                 int c;
78473 #endif
78474                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
78475                 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
78476                 d = DUK_TVAL_GET_DOUBLE(tv);
78477 #if defined(DUK_USE_PREFER_SIZE)
78478                 c = DUK_FPCLASSIFY((double) d);
78479                 if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
78480                         return 0;
78481                 } else {
78482                         return 1;
78483                 }
78484 #else
78485                 DUK_ASSERT(duk_double_is_nan_or_zero(d) == 0 || duk_double_is_nan_or_zero(d) == 1);
78486                 return duk_double_is_nan_or_zero(d) ^ 1;
78487 #endif
78488         }
78489         }
78490         DUK_UNREACHABLE();
78491 }
78492
78493 /*
78494  *  ToNumber()  (E5 Section 9.3)
78495  *
78496  *  Value to convert must be on stack top, and is popped before exit.
78497  *
78498  *  See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
78499  *       http://www.cs.indiana.edu/~burger/fp/index.html
78500  *
78501  *  Notes on the conversion:
78502  *
78503  *    - There are specific requirements on the accuracy of the conversion
78504  *      through a "Mathematical Value" (MV), so this conversion is not
78505  *      trivial.
78506  *
78507  *    - Quick rejects (e.g. based on first char) are difficult because
78508  *      the grammar allows leading and trailing white space.
78509  *
78510  *    - Quick reject based on string length is difficult even after
78511  *      accounting for white space; there may be arbitrarily many
78512  *      decimal digits.
78513  *
78514  *    - Standard grammar allows decimal values ("123"), hex values
78515  *      ("0x123") and infinities
78516  *
78517  *    - Unlike source code literals, ToNumber() coerces empty strings
78518  *      and strings with only whitespace to zero (not NaN).
78519  */
78520
78521 /* E5 Section 9.3.1 */
78522 DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
78523         duk_small_uint_t s2n_flags;
78524         duk_double_t d;
78525
78526         DUK_ASSERT(duk_is_string(thr, -1));
78527
78528         /* Quite lenient, e.g. allow empty as zero, but don't allow trailing
78529          * garbage.
78530          */
78531         s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
78532                     DUK_S2N_FLAG_ALLOW_EXP |
78533                     DUK_S2N_FLAG_ALLOW_PLUS |
78534                     DUK_S2N_FLAG_ALLOW_MINUS |
78535                     DUK_S2N_FLAG_ALLOW_INF |
78536                     DUK_S2N_FLAG_ALLOW_FRAC |
78537                     DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
78538                     DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
78539                     DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
78540                     DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
78541                     DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT |
78542                     DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT |
78543                     DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT;
78544
78545         duk_numconv_parse(thr, 10 /*radix*/, s2n_flags);
78546
78547 #if defined(DUK_USE_PREFER_SIZE)
78548         d = duk_get_number(thr, -1);
78549         duk_pop_unsafe(thr);
78550 #else
78551         thr->valstack_top--;
78552         DUK_ASSERT(DUK_TVAL_IS_NUMBER(thr->valstack_top));
78553         DUK_ASSERT(DUK_TVAL_IS_DOUBLE(thr->valstack_top));  /* no fastint conversion in numconv now */
78554         DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(thr->valstack_top));
78555         d = DUK_TVAL_GET_DOUBLE(thr->valstack_top);  /* assumes not a fastint */
78556         DUK_TVAL_SET_UNDEFINED(thr->valstack_top);
78557 #endif
78558
78559         return d;
78560 }
78561
78562 DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
78563         DUK_ASSERT(thr != NULL);
78564         DUK_ASSERT(tv != NULL);
78565
78566         switch (DUK_TVAL_GET_TAG(tv)) {
78567         case DUK_TAG_UNDEFINED: {
78568                 /* return a specific NaN (although not strictly necessary) */
78569                 duk_double_union du;
78570                 DUK_DBLUNION_SET_NAN(&du);
78571                 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
78572                 return du.d;
78573         }
78574         case DUK_TAG_NULL: {
78575                 /* +0.0 */
78576                 return 0.0;
78577         }
78578         case DUK_TAG_BOOLEAN: {
78579                 if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
78580                         return 1.0;
78581                 }
78582                 return 0.0;
78583         }
78584         case DUK_TAG_STRING: {
78585                 /* For Symbols ToNumber() is always a TypeError. */
78586                 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
78587                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
78588                         DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL);
78589                         DUK_WO_NORETURN(return 0.0;);
78590                 }
78591                 duk_push_hstring(thr, h);
78592                 return duk__tonumber_string_raw(thr);
78593         }
78594         case DUK_TAG_BUFFER:  /* plain buffer treated like object */
78595         case DUK_TAG_OBJECT: {
78596                 duk_double_t d;
78597                 duk_push_tval(thr, tv);
78598                 duk_to_primitive(thr, -1, DUK_HINT_NUMBER);  /* 'tv' becomes invalid */
78599
78600                 /* recursive call for a primitive value (guaranteed not to cause second
78601                  * recursion).
78602                  */
78603                 DUK_ASSERT(duk_get_tval(thr, -1) != NULL);
78604                 d = duk_js_tonumber(thr, duk_get_tval(thr, -1));
78605
78606                 duk_pop_unsafe(thr);
78607                 return d;
78608         }
78609         case DUK_TAG_POINTER: {
78610                 /* Coerce like boolean */
78611                 void *p = DUK_TVAL_GET_POINTER(tv);
78612                 return (p != NULL ? 1.0 : 0.0);
78613         }
78614         case DUK_TAG_LIGHTFUNC: {
78615                 /* +(function(){}) -> NaN */
78616                 return DUK_DOUBLE_NAN;
78617         }
78618 #if defined(DUK_USE_FASTINT)
78619         case DUK_TAG_FASTINT:
78620                 return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
78621 #endif
78622         default: {
78623                 /* number */
78624                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
78625                 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
78626                 return DUK_TVAL_GET_DOUBLE(tv);
78627         }
78628         }
78629
78630         DUK_UNREACHABLE();
78631 }
78632
78633 /*
78634  *  ToInteger()  (E5 Section 9.4)
78635  */
78636
78637 /* exposed, used by e.g. duk_bi_date.c */
78638 DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
78639 #if defined(DUK_USE_PREFER_SIZE)
78640         duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
78641
78642         if (DUK_UNLIKELY(c == DUK_FP_NAN)) {
78643                 return 0.0;
78644         } else if (DUK_UNLIKELY(c == DUK_FP_INFINITE)) {
78645                 return x;
78646         } else {
78647                 /* Finite, including neg/pos zero.  Neg zero sign must be
78648                  * preserved.
78649                  */
78650                 return duk_double_trunc_towards_zero(x);
78651         }
78652 #else  /* DUK_USE_PREFER_SIZE */
78653         /* NaN and Infinity have the same exponent so it's a cheap
78654          * initial check for the rare path.
78655          */
78656         if (DUK_UNLIKELY(duk_double_is_nan_or_inf(x) != 0U)) {
78657                 if (duk_double_is_nan(x)) {
78658                         return 0.0;
78659                 } else {
78660                         return x;
78661                 }
78662         } else {
78663                 return duk_double_trunc_towards_zero(x);
78664         }
78665 #endif  /* DUK_USE_PREFER_SIZE */
78666 }
78667
78668 DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
78669         /* XXX: fastint */
78670         duk_double_t d = duk_js_tonumber(thr, tv);  /* invalidates tv */
78671         return duk_js_tointeger_number(d);
78672 }
78673
78674 /*
78675  *  ToInt32(), ToUint32(), ToUint16()  (E5 Sections 9.5, 9.6, 9.7)
78676  */
78677
78678 /* combined algorithm matching E5 Sections 9.5 and 9.6 */
78679 DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) {
78680 #if defined (DUK_USE_PREFER_SIZE)
78681         duk_small_int_t c;
78682 #endif
78683
78684 #if defined (DUK_USE_PREFER_SIZE)
78685         c = (duk_small_int_t) DUK_FPCLASSIFY(x);
78686         if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
78687                 return 0.0;
78688         }
78689 #else
78690         if (duk_double_is_nan_zero_inf(x)) {
78691                 return 0.0;
78692         }
78693 #endif
78694
78695         /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
78696         x = duk_double_trunc_towards_zero(x);
78697
78698         /* NOTE: fmod(x) result sign is same as sign of x, which
78699          * differs from what Javascript wants (see Section 9.6).
78700          */
78701
78702         x = DUK_FMOD(x, DUK_DOUBLE_2TO32);    /* -> x in ]-2**32, 2**32[ */
78703
78704         if (x < 0.0) {
78705                 x += DUK_DOUBLE_2TO32;
78706         }
78707         DUK_ASSERT(x >= 0 && x < DUK_DOUBLE_2TO32);  /* -> x in [0, 2**32[ */
78708
78709         if (is_toint32) {
78710                 if (x >= DUK_DOUBLE_2TO31) {
78711                         /* x in [2**31, 2**32[ */
78712
78713                         x -= DUK_DOUBLE_2TO32;  /* -> x in [-2**31,2**31[ */
78714                 }
78715         }
78716
78717         return x;
78718 }
78719
78720 DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) {
78721         duk_double_t d;
78722
78723 #if defined(DUK_USE_FASTINT)
78724         if (DUK_TVAL_IS_FASTINT(tv)) {
78725                 return DUK_TVAL_GET_FASTINT_I32(tv);
78726         }
78727 #endif
78728
78729         d = duk_js_tonumber(thr, tv);  /* invalidates tv */
78730         d = duk__toint32_touint32_helper(d, 1);
78731         DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
78732         DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0);  /* [-0x80000000,0x7fffffff] */
78733         DUK_ASSERT(d == ((duk_double_t) ((duk_int32_t) d)));  /* whole, won't clip */
78734         return (duk_int32_t) d;
78735 }
78736
78737
78738 DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) {
78739         duk_double_t d;
78740
78741 #if defined(DUK_USE_FASTINT)
78742         if (DUK_TVAL_IS_FASTINT(tv)) {
78743                 return DUK_TVAL_GET_FASTINT_U32(tv);
78744         }
78745 #endif
78746
78747         d = duk_js_tonumber(thr, tv);  /* invalidates tv */
78748         d = duk__toint32_touint32_helper(d, 0);
78749         DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
78750         DUK_ASSERT(d >= 0.0 && d <= 4294967295.0);  /* [0x00000000, 0xffffffff] */
78751         DUK_ASSERT(d == ((duk_double_t) ((duk_uint32_t) d)));  /* whole, won't clip */
78752         return (duk_uint32_t) d;
78753
78754 }
78755
78756 DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
78757         /* should be a safe way to compute this */
78758         return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU);
78759 }
78760
78761 /*
78762  *  ToString()  (E5 Section 9.8)
78763  *  ToObject()  (E5 Section 9.9)
78764  *  CheckObjectCoercible()  (E5 Section 9.10)
78765  *  IsCallable()  (E5 Section 9.11)
78766  *
78767  *  ==> implemented in the API.
78768  */
78769
78770 /*
78771  *  Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
78772  *  9.12).  These have much in common so they can share some helpers.
78773  *
78774  *  Future work notes:
78775  *
78776  *    - Current implementation (and spec definition) has recursion; this should
78777  *      be fixed if possible.
78778  *
78779  *    - String-to-number coercion should be possible without going through the
78780  *      value stack (and be more compact) if a shared helper is invoked.
78781  */
78782
78783 /* Note that this is the same operation for strict and loose equality:
78784  *  - E5 Section 11.9.3, step 1.c (loose)
78785  *  - E5 Section 11.9.6, step 4 (strict)
78786  */
78787
78788 DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) {
78789 #if defined(DUK_USE_PARANOID_MATH)
78790         /* Straightforward algorithm, makes fewer compiler assumptions. */
78791         duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
78792         duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
78793         if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) {
78794                 return 0;
78795         }
78796         if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
78797                 return 1;
78798         }
78799         if (x == y) {
78800                 return 1;
78801         }
78802         return 0;
78803 #else  /* DUK_USE_PARANOID_MATH */
78804         /* Better equivalent algorithm.  If the compiler is compliant, C and
78805          * ECMAScript semantics are identical for this particular comparison.
78806          * In particular, NaNs must never compare equal and zeroes must compare
78807          * equal regardless of sign.  Could also use a macro, but this inlines
78808          * already nicely (no difference on gcc, for instance).
78809          */
78810         if (x == y) {
78811                 /* IEEE requires that NaNs compare false */
78812                 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
78813                 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
78814                 return 1;
78815         } else {
78816                 /* IEEE requires that zeros compare the same regardless
78817                  * of their signed, so if both x and y are zeroes, they
78818                  * are caught above.
78819                  */
78820                 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
78821                 return 0;
78822         }
78823 #endif  /* DUK_USE_PARANOID_MATH */
78824 }
78825
78826 DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
78827 #if defined(DUK_USE_PARANOID_MATH)
78828         duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
78829         duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
78830
78831         if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) {
78832                 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
78833                 return 1;
78834         }
78835         if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
78836                 /* Note: cannot assume that a non-zero return value of signbit() would
78837                  * always be the same -- hence cannot (portably) use something like:
78838                  *
78839                  *     signbit(x) == signbit(y)
78840                  */
78841                 duk_small_int_t sx = DUK_SIGNBIT(x) ? 1 : 0;
78842                 duk_small_int_t sy = DUK_SIGNBIT(y) ? 1 : 0;
78843                 return (sx == sy);
78844         }
78845
78846         /* normal comparison; known:
78847          *   - both x and y are not NaNs (but one of them can be)
78848          *   - both x and y are not zero (but one of them can be)
78849          *   - x and y may be denormal or infinite
78850          */
78851
78852         return (x == y);
78853 #else  /* DUK_USE_PARANOID_MATH */
78854         duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
78855         duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
78856
78857         if (x == y) {
78858                 /* IEEE requires that NaNs compare false */
78859                 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
78860                 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
78861
78862                 /* Using classification has smaller footprint than direct comparison. */
78863                 if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) {
78864                         /* Note: cannot assume that a non-zero return value of signbit() would
78865                          * always be the same -- hence cannot (portably) use something like:
78866                          *
78867                          *     signbit(x) == signbit(y)
78868                          */
78869                         return duk_double_same_sign(x, y);
78870                 }
78871                 return 1;
78872         } else {
78873                 /* IEEE requires that zeros compare the same regardless
78874                  * of their sign, so if both x and y are zeroes, they
78875                  * are caught above.
78876                  */
78877                 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
78878
78879                 /* Difference to non-strict/strict comparison is that NaNs compare
78880                  * equal and signed zero signs matter.
78881                  */
78882                 if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) {
78883                         /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
78884                         return 1;
78885                 }
78886                 return 0;
78887         }
78888 #endif  /* DUK_USE_PARANOID_MATH */
78889 }
78890
78891 DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) {
78892         duk_uint_t type_mask_x;
78893         duk_uint_t type_mask_y;
78894
78895         /* If flags != 0 (strict or SameValue), thr can be NULL.  For loose
78896          * equals comparison it must be != NULL.
78897          */
78898         DUK_ASSERT(flags != 0 || thr != NULL);
78899
78900         /*
78901          *  Same type?
78902          *
78903          *  Note: since number values have no explicit tag in the 8-byte
78904          *  representation, need the awkward if + switch.
78905          */
78906
78907 #if defined(DUK_USE_FASTINT)
78908         if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
78909                 if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) {
78910                         return 1;
78911                 } else {
78912                         return 0;
78913                 }
78914         }
78915         else
78916 #endif
78917         if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
78918                 duk_double_t d1, d2;
78919
78920                 /* Catches both doubles and cases where only one argument is
78921                  * a fastint so can't assume a double.
78922                  */
78923                 d1 = DUK_TVAL_GET_NUMBER(tv_x);
78924                 d2 = DUK_TVAL_GET_NUMBER(tv_y);
78925                 if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
78926                         /* SameValue */
78927                         return duk__js_samevalue_number(d1, d2);
78928                 } else {
78929                         /* equals and strict equals */
78930                         return duk__js_equals_number(d1, d2);
78931                 }
78932         } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
78933                 switch (DUK_TVAL_GET_TAG(tv_x)) {
78934                 case DUK_TAG_UNDEFINED:
78935                 case DUK_TAG_NULL: {
78936                         return 1;
78937                 }
78938                 case DUK_TAG_BOOLEAN: {
78939                         return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
78940                 }
78941                 case DUK_TAG_POINTER: {
78942                         return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
78943                 }
78944                 case DUK_TAG_STRING:
78945                 case DUK_TAG_OBJECT: {
78946                         /* Heap pointer comparison suffices for strings and objects.
78947                          * Symbols compare equal if they have the same internal
78948                          * representation; again heap pointer comparison suffices.
78949                          */
78950                         return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
78951                 }
78952                 case DUK_TAG_BUFFER: {
78953                         /* In Duktape 2.x plain buffers mimic Uint8Array objects
78954                          * so always compare by heap pointer.  In Duktape 1.x
78955                          * strict comparison would compare heap pointers and
78956                          * non-strict would compare contents.
78957                          */
78958                         return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
78959                 }
78960                 case DUK_TAG_LIGHTFUNC: {
78961                         /* At least 'magic' has a significant impact on function
78962                          * identity.
78963                          */
78964                         duk_small_uint_t lf_flags_x;
78965                         duk_small_uint_t lf_flags_y;
78966                         duk_c_function func_x;
78967                         duk_c_function func_y;
78968
78969                         DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x);
78970                         DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y);
78971                         return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0;
78972                 }
78973 #if defined(DUK_USE_FASTINT)
78974                 case DUK_TAG_FASTINT:
78975 #endif
78976                 default: {
78977                         DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
78978                         DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y));
78979                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
78980                         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y));
78981                         DUK_UNREACHABLE();
78982                         return 0;
78983                 }
78984                 }
78985         }
78986
78987         if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
78988                 return 0;
78989         }
78990
78991         DUK_ASSERT(flags == 0);  /* non-strict equality from here on */
78992
78993         /*
78994          *  Types are different; various cases for non-strict comparison
78995          *
78996          *  Since comparison is symmetric, we use a "swap trick" to reduce
78997          *  code size.
78998          */
78999
79000         type_mask_x = duk_get_type_mask_tval(tv_x);
79001         type_mask_y = duk_get_type_mask_tval(tv_y);
79002
79003         /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
79004         if ((type_mask_x & (DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_NULL)) &&
79005             (type_mask_y & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED))) {
79006                 return 1;
79007         }
79008
79009         /* Number/string -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
79010         if ((type_mask_x & DUK_TYPE_MASK_NUMBER) && (type_mask_y & DUK_TYPE_MASK_STRING)) {
79011                 if (!DUK_TVAL_STRING_IS_SYMBOL(tv_y)) {
79012                         duk_double_t d1, d2;
79013                         d1 = DUK_TVAL_GET_NUMBER(tv_x);
79014                         d2 = duk_to_number_tval(thr, tv_y);
79015                         return duk__js_equals_number(d1, d2);
79016                 }
79017         }
79018         if ((type_mask_x & DUK_TYPE_MASK_STRING) && (type_mask_y & DUK_TYPE_MASK_NUMBER)) {
79019                 if (!DUK_TVAL_STRING_IS_SYMBOL(tv_x)) {
79020                         duk_double_t d1, d2;
79021                         d1 = DUK_TVAL_GET_NUMBER(tv_y);
79022                         d2 = duk_to_number_tval(thr, tv_x);
79023                         return duk__js_equals_number(d1, d2);
79024                 }
79025         }
79026
79027         /* Boolean/any -> coerce boolean to number and try again.  If boolean is
79028          * compared to a pointer, the final comparison after coercion now always
79029          * yields false (as pointer vs. number compares to false), but this is
79030          * not special cased.
79031          *
79032          * ToNumber(bool) is +1.0 or 0.0.  Tagged boolean value is always 0 or 1.
79033          */
79034         if (type_mask_x & DUK_TYPE_MASK_BOOLEAN) {
79035                 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_x) == 0 || DUK_TVAL_GET_BOOLEAN(tv_x) == 1);
79036                 duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_x));
79037                 duk_push_tval(thr, tv_y);
79038                 goto recursive_call;
79039         }
79040         if (type_mask_y & DUK_TYPE_MASK_BOOLEAN) {
79041                 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
79042                 duk_push_tval(thr, tv_x);
79043                 duk_push_uint(thr, DUK_TVAL_GET_BOOLEAN(tv_y));
79044                 goto recursive_call;
79045         }
79046
79047         /* String-number-symbol/object -> coerce object to primitive (apparently without hint), then try again. */
79048         if ((type_mask_x & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER)) &&
79049             (type_mask_y & DUK_TYPE_MASK_OBJECT)) {
79050                 /* No symbol check needed because symbols and strings are accepted. */
79051                 duk_push_tval(thr, tv_x);
79052                 duk_push_tval(thr, tv_y);
79053                 duk_to_primitive(thr, -1, DUK_HINT_NONE);  /* apparently no hint? */
79054                 goto recursive_call;
79055         }
79056         if ((type_mask_x & DUK_TYPE_MASK_OBJECT) &&
79057             (type_mask_y & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER))) {
79058                 /* No symbol check needed because symbols and strings are accepted. */
79059                 duk_push_tval(thr, tv_x);
79060                 duk_push_tval(thr, tv_y);
79061                 duk_to_primitive(thr, -2, DUK_HINT_NONE);  /* apparently no hint? */
79062                 goto recursive_call;
79063         }
79064
79065         /* Nothing worked -> not equal. */
79066         return 0;
79067
79068  recursive_call:
79069         /* Shared code path to call the helper again with arguments on stack top. */
79070         {
79071                 duk_bool_t rc;
79072                 rc = duk_js_equals_helper(thr,
79073                                           DUK_GET_TVAL_NEGIDX(thr, -2),
79074                                           DUK_GET_TVAL_NEGIDX(thr, -1),
79075                                           0 /*flags:nonstrict*/);
79076                 duk_pop_2_unsafe(thr);
79077                 return rc;
79078         }
79079 }
79080
79081 /*
79082  *  Comparisons (x >= y, x > y, x <= y, x < y)
79083  *
79084  *  E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first
79085  *  flags to get the rest.
79086  */
79087
79088 /* XXX: this should probably just operate on the stack top, because it
79089  * needs to push stuff on the stack anyway...
79090  */
79091
79092 DUK_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) {
79093         duk_size_t prefix_len;
79094         duk_small_int_t rc;
79095
79096         prefix_len = (len1 <= len2 ? len1 : len2);
79097
79098         /* duk_memcmp() is guaranteed to return zero (equal) for zero length
79099          * inputs.
79100          */
79101         rc = duk_memcmp_unsafe((const void *) buf1,
79102                                (const void *) buf2,
79103                                (size_t) prefix_len);
79104
79105         if (rc < 0) {
79106                 return -1;
79107         } else if (rc > 0) {
79108                 return 1;
79109         }
79110
79111         /* prefix matches, lengths matter now */
79112         if (len1 < len2) {
79113                 /* e.g. "x" < "xx" */
79114                 return -1;
79115         } else if (len1 > len2) {
79116                 return 1;
79117         }
79118
79119         return 0;
79120 }
79121
79122 DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) {
79123         /*
79124          *  String comparison (E5 Section 11.8.5, step 4), which
79125          *  needs to compare codepoint by codepoint.
79126          *
79127          *  However, UTF-8 allows us to use strcmp directly: the shared
79128          *  prefix will be encoded identically (UTF-8 has unique encoding)
79129          *  and the first differing character can be compared with a simple
79130          *  unsigned byte comparison (which strcmp does).
79131          *
79132          *  This will not work properly for non-xutf-8 strings, but this
79133          *  is not an issue for compliance.
79134          */
79135
79136         DUK_ASSERT(h1 != NULL);
79137         DUK_ASSERT(h2 != NULL);
79138
79139         return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1),
79140                                    (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2),
79141                                    (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1),
79142                                    (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2));
79143 }
79144
79145 #if 0  /* unused */
79146 DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) {
79147         /* Similar to String comparison. */
79148
79149         DUK_ASSERT(h1 != NULL);
79150         DUK_ASSERT(h2 != NULL);
79151         DUK_UNREF(heap);
79152
79153         return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1),
79154                                    (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2),
79155                                    (duk_size_t) DUK_HBUFFER_GET_SIZE(h1),
79156                                    (duk_size_t) DUK_HBUFFER_GET_SIZE(h2));
79157 }
79158 #endif
79159
79160 #if defined(DUK_USE_FASTINT)
79161 DUK_LOCAL duk_bool_t duk__compare_fastint(duk_bool_t retval, duk_int64_t v1, duk_int64_t v2) {
79162         DUK_ASSERT(retval == 0 || retval == 1);
79163         if (v1 < v2) {
79164                 return retval ^ 1;
79165         } else {
79166                 return retval;
79167         }
79168 }
79169 #endif
79170
79171 #if defined(DUK_USE_PARANOID_MATH)
79172 DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) {
79173         duk_small_int_t c1, s1, c2, s2;
79174
79175         DUK_ASSERT(retval == 0 || retval == 1);
79176         c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
79177         s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
79178         c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
79179         s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
79180
79181         if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
79182                 return 0;  /* Always false, regardless of negation. */
79183         }
79184
79185         if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
79186                 /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
79187                  * steps e, f, and g.
79188                  */
79189                 return retval;  /* false */
79190         }
79191
79192         if (d1 == d2) {
79193                 return retval;  /* false */
79194         }
79195
79196         if (c1 == DUK_FP_INFINITE && s1 == 0) {
79197                 /* x == +Infinity */
79198                 return retval;  /* false */
79199         }
79200
79201         if (c2 == DUK_FP_INFINITE && s2 == 0) {
79202                 /* y == +Infinity */
79203                 return retval ^ 1;  /* true */
79204         }
79205
79206         if (c2 == DUK_FP_INFINITE && s2 != 0) {
79207                 /* y == -Infinity */
79208                 return retval;  /* false */
79209         }
79210
79211         if (c1 == DUK_FP_INFINITE && s1 != 0) {
79212                 /* x == -Infinity */
79213                 return retval ^ 1;  /* true */
79214         }
79215
79216         if (d1 < d2) {
79217                 return retval ^ 1;  /* true */
79218         }
79219
79220         return retval;  /* false */
79221 }
79222 #else  /* DUK_USE_PARANOID_MATH */
79223 DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) {
79224         /* This comparison tree relies doesn't match the exact steps in
79225          * E5 Section 11.8.5 but should produce the same results.  The
79226          * steps rely on exact IEEE semantics for NaNs, etc.
79227          */
79228
79229         DUK_ASSERT(retval == 0 || retval == 1);
79230         if (d1 < d2) {
79231                 /* In no case should both (d1 < d2) and (d2 < d1) be true.
79232                  * It's possible that neither is true though, and that's
79233                  * handled below.
79234                  */
79235                 DUK_ASSERT(!(d2 < d1));
79236
79237                 /* - d1 < d2, both d1/d2 are normals (not Infinity, not NaN)
79238                  * - d2 is +Infinity, d1 != +Infinity and NaN
79239                  * - d1 is -Infinity, d2 != -Infinity and NaN
79240                  */
79241                 return retval ^ 1;
79242         } else {
79243                 if (d2 < d1) {
79244                         /* - !(d1 < d2), both d1/d2 are normals (not Infinity, not NaN)
79245                          * - d1 is +Infinity, d2 != +Infinity and NaN
79246                          * - d2 is -Infinity, d1 != -Infinity and NaN
79247                          */
79248                         return retval;
79249                 } else {
79250                         /* - d1 and/or d2 is NaN
79251                          * - d1 and d2 are both +/- 0
79252                          * - d1 == d2 (including infinities)
79253                          */
79254                         if (duk_double_is_nan(d1) || duk_double_is_nan(d2)) {
79255                                 /* Note: undefined from Section 11.8.5 always
79256                                  * results in false return (see e.g. Section
79257                                  * 11.8.3) - hence special treatment here.
79258                                  */
79259                                 return 0;  /* zero regardless of negation */
79260                         } else {
79261                                 return retval;
79262                         }
79263                 }
79264         }
79265 }
79266 #endif  /* DUK_USE_PARANOID_MATH */
79267
79268 DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_t flags) {
79269         duk_double_t d1, d2;
79270         duk_small_int_t rc;
79271         duk_bool_t retval;
79272
79273         DUK_ASSERT(DUK_COMPARE_FLAG_NEGATE == 1);  /* Rely on this flag being lowest. */
79274         retval = flags & DUK_COMPARE_FLAG_NEGATE;
79275         DUK_ASSERT(retval == 0 || retval == 1);
79276
79277         /* Fast path for fastints */
79278 #if defined(DUK_USE_FASTINT)
79279         if (DUK_LIKELY(DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y))) {
79280                 return duk__compare_fastint(retval,
79281                                             DUK_TVAL_GET_FASTINT(tv_x),
79282                                             DUK_TVAL_GET_FASTINT(tv_y));
79283         }
79284 #endif  /* DUK_USE_FASTINT */
79285
79286         /* Fast path for numbers (one of which may be a fastint) */
79287 #if !defined(DUK_USE_PREFER_SIZE)
79288         if (DUK_LIKELY(DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y))) {
79289                 return duk__compare_number(retval,
79290                                            DUK_TVAL_GET_NUMBER(tv_x),
79291                                            DUK_TVAL_GET_NUMBER(tv_y));
79292         }
79293 #endif
79294
79295         /* Slow path */
79296
79297         duk_push_tval(thr, tv_x);
79298         duk_push_tval(thr, tv_y);
79299
79300         if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
79301                 duk_to_primitive(thr, -2, DUK_HINT_NUMBER);
79302                 duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
79303         } else {
79304                 duk_to_primitive(thr, -1, DUK_HINT_NUMBER);
79305                 duk_to_primitive(thr, -2, DUK_HINT_NUMBER);
79306         }
79307
79308         /* Note: reuse variables */
79309         tv_x = DUK_GET_TVAL_NEGIDX(thr, -2);
79310         tv_y = DUK_GET_TVAL_NEGIDX(thr, -1);
79311
79312         if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
79313                 duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
79314                 duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
79315                 DUK_ASSERT(h1 != NULL);
79316                 DUK_ASSERT(h2 != NULL);
79317
79318                 if (DUK_LIKELY(!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2))) {
79319                         rc = duk_js_string_compare(h1, h2);
79320                         duk_pop_2_unsafe(thr);
79321                         if (rc < 0) {
79322                                 return retval ^ 1;
79323                         } else {
79324                                 return retval;
79325                         }
79326                 }
79327
79328                 /* One or both are Symbols: fall through to handle in the
79329                  * generic path.  Concretely, ToNumber() will fail.
79330                  */
79331         }
79332
79333         /* Ordering should not matter (E5 Section 11.8.5, step 3.a). */
79334 #if 0
79335         if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
79336                 d1 = duk_to_number_m2(thr);
79337                 d2 = duk_to_number_m1(thr);
79338         } else {
79339                 d2 = duk_to_number_m1(thr);
79340                 d1 = duk_to_number_m2(thr);
79341         }
79342 #endif
79343         d1 = duk_to_number_m2(thr);
79344         d2 = duk_to_number_m1(thr);
79345
79346         /* We want to duk_pop_2_unsafe(thr); because the values are numbers
79347          * no decref check is needed.
79348          */
79349 #if defined(DUK_USE_PREFER_SIZE)
79350         duk_pop_2_nodecref_unsafe(thr);
79351 #else
79352         DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -2)));
79353         DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(thr, -1)));
79354         DUK_ASSERT(duk_get_top(thr) >= 2);
79355         thr->valstack_top -= 2;
79356         tv_x = thr->valstack_top;
79357         tv_y = tv_x + 1;
79358         DUK_TVAL_SET_UNDEFINED(tv_x);  /* Value stack policy */
79359         DUK_TVAL_SET_UNDEFINED(tv_y);
79360 #endif
79361
79362         return duk__compare_number(retval, d1, d2);
79363 }
79364
79365 /*
79366  *  instanceof
79367  */
79368
79369 /*
79370  *  ES2015 Section 7.3.19 describes the OrdinaryHasInstance() algorithm
79371  *  which covers both bound and non-bound functions; in effect the algorithm
79372  *  includes E5 Sections 11.8.6, 15.3.5.3, and 15.3.4.5.3.
79373  *
79374  *  ES2015 Section 12.9.4 describes the instanceof operator which first
79375  *  checks @@hasInstance well-known symbol and falls back to
79376  *  OrdinaryHasInstance().
79377  *
79378  *  Limited Proxy support: don't support 'getPrototypeOf' trap but
79379  *  continue lookup in Proxy target if the value is a Proxy.
79380  */
79381
79382 DUK_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) {
79383         duk_hobject *func;
79384         duk_hobject *val;
79385         duk_hobject *proto;
79386         duk_tval *tv;
79387         duk_bool_t skip_first;
79388         duk_uint_t sanity;
79389
79390         /*
79391          *  Get the values onto the stack first.  It would be possible to cover
79392          *  some normal cases without resorting to the value stack.
79393          *
79394          *  The right hand side could be a light function (as they generally
79395          *  behave like objects).  Light functions never have a 'prototype'
79396          *  property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
79397          *  Using duk_require_hobject() is thus correct (except for error msg).
79398          */
79399
79400         duk_push_tval(thr, tv_x);
79401         duk_push_tval(thr, tv_y);
79402         func = duk_require_hobject(thr, -1);
79403         DUK_ASSERT(func != NULL);
79404
79405 #if defined(DUK_USE_SYMBOL_BUILTIN)
79406         /*
79407          *  @@hasInstance check, ES2015 Section 12.9.4, Steps 2-4.
79408          */
79409         if (!skip_sym_check) {
79410                 if (duk_get_method_stridx(thr, -1, DUK_STRIDX_WELLKNOWN_SYMBOL_HAS_INSTANCE)) {
79411                         /* [ ... lhs rhs func ] */
79412                         duk_insert(thr, -3);    /* -> [ ... func lhs rhs ] */
79413                         duk_swap_top(thr, -2);  /* -> [ ... func rhs(this) lhs ] */
79414                         duk_call_method(thr, 1);
79415                         return duk_to_boolean_top_pop(thr);
79416                 }
79417         }
79418 #else
79419         DUK_UNREF(skip_sym_check);
79420 #endif
79421
79422         /*
79423          *  For bound objects, [[HasInstance]] just calls the target function
79424          *  [[HasInstance]].  If that is again a bound object, repeat until
79425          *  we find a non-bound Function object.
79426          *
79427          *  The bound function chain is now "collapsed" so there can be only
79428          *  one bound function in the chain.
79429          */
79430
79431         if (!DUK_HOBJECT_IS_CALLABLE(func)) {
79432                 /*
79433                  *  Note: of native ECMAScript objects, only Function instances
79434                  *  have a [[HasInstance]] internal property.  Custom objects might
79435                  *  also have it, but not in current implementation.
79436                  *
79437                  *  XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
79438                  */
79439                 goto error_invalid_rval;
79440         }
79441
79442         if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
79443                 duk_push_tval(thr, &((duk_hboundfunc *) (void *) func)->target);
79444                 duk_replace(thr, -2);
79445                 func = duk_require_hobject(thr, -1);  /* lightfunc throws */
79446
79447                 /* Rely on Function.prototype.bind() never creating bound
79448                  * functions whose target is not proper.
79449                  */
79450                 DUK_ASSERT(func != NULL);
79451                 DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
79452         }
79453
79454         /*
79455          *  'func' is now a non-bound object which supports [[HasInstance]]
79456          *  (which here just means DUK_HOBJECT_FLAG_CALLABLE).  Move on
79457          *  to execute E5 Section 15.3.5.3.
79458          */
79459
79460         DUK_ASSERT(func != NULL);
79461         DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
79462         DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
79463
79464         /* [ ... lval rval(func) ] */
79465
79466         /* For lightfuncs, buffers, and pointers start the comparison directly
79467          * from the virtual prototype object.
79468          */
79469         skip_first = 0;
79470         tv = DUK_GET_TVAL_NEGIDX(thr, -2);
79471         switch (DUK_TVAL_GET_TAG(tv)) {
79472         case DUK_TAG_LIGHTFUNC:
79473                 val = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
79474                 DUK_ASSERT(val != NULL);
79475                 break;
79476         case DUK_TAG_BUFFER:
79477                 val = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
79478                 DUK_ASSERT(val != NULL);
79479                 break;
79480         case DUK_TAG_POINTER:
79481                 val = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
79482                 DUK_ASSERT(val != NULL);
79483                 break;
79484         case DUK_TAG_OBJECT:
79485                 skip_first = 1;  /* Ignore object itself on first round. */
79486                 val = DUK_TVAL_GET_OBJECT(tv);
79487                 DUK_ASSERT(val != NULL);
79488                 break;
79489         default:
79490                 goto pop2_and_false;
79491         }
79492         DUK_ASSERT(val != NULL);  /* Loop doesn't actually rely on this. */
79493
79494         /* Look up .prototype of rval.  Leave it on the value stack in case it
79495          * has been virtualized (e.g. getter, Proxy trap).
79496          */
79497         duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_PROTOTYPE);  /* -> [ ... lval rval rval.prototype ] */
79498 #if defined(DUK_USE_VERBOSE_ERRORS)
79499         proto = duk_get_hobject(thr, -1);
79500         if (proto == NULL) {
79501                 goto error_invalid_rval_noproto;
79502         }
79503 #else
79504         proto = duk_require_hobject(thr, -1);
79505 #endif
79506
79507         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
79508         do {
79509                 /*
79510                  *  Note: prototype chain is followed BEFORE first comparison.  This
79511                  *  means that the instanceof lval is never itself compared to the
79512                  *  rval.prototype property.  This is apparently intentional, see E5
79513                  *  Section 15.3.5.3, step 4.a.
79514                  *
79515                  *  Also note:
79516                  *
79517                  *      js> (function() {}) instanceof Function
79518                  *      true
79519                  *      js> Function instanceof Function
79520                  *      true
79521                  *
79522                  *  For the latter, h_proto will be Function.prototype, which is the
79523                  *  built-in Function prototype.  Because Function.[[Prototype]] is
79524                  *  also the built-in Function prototype, the result is true.
79525                  */
79526
79527                 if (!val) {
79528                         goto pop3_and_false;
79529                 }
79530
79531                 DUK_ASSERT(val != NULL);
79532 #if defined(DUK_USE_ES6_PROXY)
79533                 val = duk_hobject_resolve_proxy_target(val);
79534 #endif
79535
79536                 if (skip_first) {
79537                         skip_first = 0;
79538                 } else if (val == proto) {
79539                         goto pop3_and_true;
79540                 }
79541
79542                 DUK_ASSERT(val != NULL);
79543                 val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
79544         } while (--sanity > 0);
79545
79546         if (DUK_UNLIKELY(sanity == 0)) {
79547                 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
79548                 DUK_WO_NORETURN(return 0;);
79549         }
79550         DUK_UNREACHABLE();
79551
79552  pop2_and_false:
79553         duk_pop_2_unsafe(thr);
79554         return 0;
79555
79556  pop3_and_false:
79557         duk_pop_3_unsafe(thr);
79558         return 0;
79559
79560  pop3_and_true:
79561         duk_pop_3_unsafe(thr);
79562         return 1;
79563
79564  error_invalid_rval:
79565         DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL);
79566         DUK_WO_NORETURN(return 0;);
79567
79568 #if defined(DUK_USE_VERBOSE_ERRORS)
79569  error_invalid_rval_noproto:
79570         DUK_ERROR_TYPE(thr, DUK_STR_INVALID_INSTANCEOF_RVAL_NOPROTO);
79571         DUK_WO_NORETURN(return 0;);
79572 #endif
79573 }
79574
79575 #if defined(DUK_USE_SYMBOL_BUILTIN)
79576 DUK_INTERNAL duk_bool_t duk_js_instanceof_ordinary(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
79577         return duk__js_instanceof_helper(thr, tv_x, tv_y, 1 /*skip_sym_check*/);
79578 }
79579 #endif
79580
79581 DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
79582         return duk__js_instanceof_helper(thr, tv_x, tv_y, 0 /*skip_sym_check*/);
79583 }
79584
79585 /*
79586  *  in
79587  */
79588
79589 /*
79590  *  E5 Sections 11.8.7, 8.12.6.
79591  *
79592  *  Basically just a property existence check using [[HasProperty]].
79593  */
79594
79595 DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
79596         duk_bool_t retval;
79597
79598         /*
79599          *  Get the values onto the stack first.  It would be possible to cover
79600          *  some normal cases without resorting to the value stack (e.g. if
79601          *  lval is already a string).
79602          */
79603
79604         /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
79605          * must be string coerced before the internal HasProperty() algorithm is
79606          * invoked.  A fast path skipping coercion could be safely implemented for
79607          * numbers (as number-to-string coercion has no side effects).  For ES2015
79608          * proxy behavior, the trap 'key' argument must be in a string coerced
79609          * form (which is a shame).
79610          */
79611
79612         /* TypeError if rval is not an object or object like (e.g. lightfunc
79613          * or plain buffer).
79614          */
79615         duk_push_tval(thr, tv_x);
79616         duk_push_tval(thr, tv_y);
79617         duk_require_type_mask(thr, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
79618
79619         (void) duk_to_property_key_hstring(thr, -2);
79620
79621         retval = duk_hobject_hasprop(thr,
79622                                      DUK_GET_TVAL_NEGIDX(thr, -1),
79623                                      DUK_GET_TVAL_NEGIDX(thr, -2));
79624
79625         duk_pop_2_unsafe(thr);
79626         return retval;
79627 }
79628
79629 /*
79630  *  typeof
79631  *
79632  *  E5 Section 11.4.3.
79633  *
79634  *  Very straightforward.  The only question is what to return for our
79635  *  non-standard tag / object types.
79636  *
79637  *  There is an unfortunate string constant define naming problem with
79638  *  typeof return values for e.g. "Object" and "object"; careful with
79639  *  the built-in string defines.  The LC_XXX defines are used for the
79640  *  lowercase variants now.
79641  */
79642
79643 DUK_INTERNAL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x) {
79644         duk_small_uint_t stridx = 0;
79645
79646         switch (DUK_TVAL_GET_TAG(tv_x)) {
79647         case DUK_TAG_UNDEFINED: {
79648                 stridx = DUK_STRIDX_LC_UNDEFINED;
79649                 break;
79650         }
79651         case DUK_TAG_NULL: {
79652                 /* Note: not a typo, "object" is returned for a null value. */
79653                 stridx = DUK_STRIDX_LC_OBJECT;
79654                 break;
79655         }
79656         case DUK_TAG_BOOLEAN: {
79657                 stridx = DUK_STRIDX_LC_BOOLEAN;
79658                 break;
79659         }
79660         case DUK_TAG_POINTER: {
79661                 /* Implementation specific. */
79662                 stridx = DUK_STRIDX_LC_POINTER;
79663                 break;
79664         }
79665         case DUK_TAG_STRING: {
79666                 duk_hstring *str;
79667
79668                 /* All internal keys are identified as Symbols. */
79669                 str = DUK_TVAL_GET_STRING(tv_x);
79670                 DUK_ASSERT(str != NULL);
79671                 if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(str))) {
79672                         stridx = DUK_STRIDX_LC_SYMBOL;
79673                 } else {
79674                         stridx = DUK_STRIDX_LC_STRING;
79675                 }
79676                 break;
79677         }
79678         case DUK_TAG_OBJECT: {
79679                 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
79680                 DUK_ASSERT(obj != NULL);
79681                 if (DUK_HOBJECT_IS_CALLABLE(obj)) {
79682                         stridx = DUK_STRIDX_LC_FUNCTION;
79683                 } else {
79684                         stridx = DUK_STRIDX_LC_OBJECT;
79685                 }
79686                 break;
79687         }
79688         case DUK_TAG_BUFFER: {
79689                 /* Implementation specific.  In Duktape 1.x this would be
79690                  * 'buffer', in Duktape 2.x changed to 'object' because plain
79691                  * buffers now mimic Uint8Array objects.
79692                  */
79693                 stridx = DUK_STRIDX_LC_OBJECT;
79694                 break;
79695         }
79696         case DUK_TAG_LIGHTFUNC: {
79697                 stridx = DUK_STRIDX_LC_FUNCTION;
79698                 break;
79699         }
79700 #if defined(DUK_USE_FASTINT)
79701         case DUK_TAG_FASTINT:
79702 #endif
79703         default: {
79704                 /* number */
79705                 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
79706                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
79707                 stridx = DUK_STRIDX_LC_NUMBER;
79708                 break;
79709         }
79710         }
79711
79712         DUK_ASSERT_STRIDX_VALID(stridx);
79713         return stridx;
79714 }
79715
79716 /*
79717  *  Array index and length
79718  *
79719  *  Array index: E5 Section 15.4
79720  *  Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
79721  */
79722
79723 /* Compure array index from string context, or return a "not array index"
79724  * indicator.
79725  */
79726 DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string(const duk_uint8_t *str, duk_uint32_t blen) {
79727         duk_uarridx_t res;
79728
79729         /* Only strings with byte length 1-10 can be 32-bit array indices.
79730          * Leading zeroes (except '0' alone), plus/minus signs are not allowed.
79731          * We could do a lot of prechecks here, but since most strings won't
79732          * start with any digits, it's simpler to just parse the number and
79733          * fail quickly.
79734          */
79735
79736         res = 0;
79737         if (blen == 0) {
79738                 goto parse_fail;
79739         }
79740         do {
79741                 duk_uarridx_t dig;
79742                 dig = (duk_uarridx_t) (*str++) - DUK_ASC_0;
79743
79744                 if (dig <= 9U) {
79745                         /* Careful overflow handling.  When multiplying by 10:
79746                          * - 0x19999998 x 10 = 0xfffffff0: no overflow, and adding
79747                          *   0...9 is safe.
79748                          * - 0x19999999 x 10 = 0xfffffffa: no overflow, adding
79749                          *   0...5 is safe, 6...9 overflows.
79750                          * - 0x1999999a x 10 = 0x100000004: always overflow.
79751                          */
79752                         if (DUK_UNLIKELY(res >= 0x19999999UL)) {
79753                                 if (res >= 0x1999999aUL) {
79754                                         /* Always overflow. */
79755                                         goto parse_fail;
79756                                 }
79757                                 DUK_ASSERT(res == 0x19999999UL);
79758                                 if (dig >= 6U) {
79759                                         goto parse_fail;
79760                                 }
79761                                 res = 0xfffffffaUL + dig;
79762                                 DUK_ASSERT(res >= 0xfffffffaUL);
79763                                 DUK_ASSERT_DISABLE(res <= 0xffffffffUL);  /* range */
79764                         } else {
79765                                 res = res * 10U + dig;
79766                                 if (DUK_UNLIKELY(res == 0)) {
79767                                         /* If 'res' is 0, previous 'res' must
79768                                          * have been 0 and we scanned in a zero.
79769                                          * This is only allowed if blen == 1,
79770                                          * i.e. the exact string '0'.
79771                                          */
79772                                         if (blen == (duk_uint32_t) 1) {
79773                                                 return 0;
79774                                         }
79775                                         goto parse_fail;
79776                                 }
79777                         }
79778                 } else {
79779                         /* Because 'dig' is unsigned, catches both values
79780                          * above '9' and below '0'.
79781                          */
79782                         goto parse_fail;
79783                 }
79784         } while (--blen > 0);
79785
79786         return res;
79787
79788  parse_fail:
79789         return DUK_HSTRING_NO_ARRAY_INDEX;
79790 }
79791
79792 #if !defined(DUK_USE_HSTRING_ARRIDX)
79793 /* Get array index for a string which is known to be an array index.  This helper
79794  * is needed when duk_hstring doesn't concretely store the array index, but strings
79795  * are flagged as array indices at intern time.
79796  */
79797 DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast_known(duk_hstring *h) {
79798         const duk_uint8_t *p;
79799         duk_uarridx_t res;
79800         duk_uint8_t t;
79801
79802         DUK_ASSERT(h != NULL);
79803         DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(h));
79804
79805         p = DUK_HSTRING_GET_DATA(h);
79806         res = 0;
79807         for (;;) {
79808                 t = *p++;
79809                 if (DUK_UNLIKELY(t == 0)) {
79810                         /* Scanning to NUL is always safe for interned strings. */
79811                         break;
79812                 }
79813                 DUK_ASSERT(t >= (duk_uint8_t) DUK_ASC_0 && t <= (duk_uint8_t) DUK_ASC_9);
79814                 res = res * 10U + (duk_uarridx_t) t - (duk_uarridx_t) DUK_ASC_0;
79815         }
79816         return res;
79817 }
79818
79819 DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_hstring_fast(duk_hstring *h) {
79820         DUK_ASSERT(h != NULL);
79821         if (!DUK_HSTRING_HAS_ARRIDX(h)) {
79822                 return DUK_HSTRING_NO_ARRAY_INDEX;
79823         }
79824         return duk_js_to_arrayindex_hstring_fast_known(h);
79825 }
79826 #endif  /* DUK_USE_HSTRING_ARRIDX */
79827 #line 1 "duk_js_var.c"
79828 /*
79829  *  Identifier access and function closure handling.
79830  *
79831  *  Provides the primitives for slow path identifier accesses: GETVAR,
79832  *  PUTVAR, DELVAR, etc.  The fast path, direct register accesses, should
79833  *  be used for most identifier accesses.  Consequently, these slow path
79834  *  primitives should be optimized for maximum compactness.
79835  *
79836  *  ECMAScript environment records (declarative and object) are represented
79837  *  as internal objects with control keys.  Environment records have a
79838  *  parent record ("outer environment reference") which is represented by
79839  *  the implicit prototype for technical reasons (in other words, it is a
79840  *  convenient field).  The prototype chain is not followed in the ordinary
79841  *  sense for variable lookups.
79842  *
79843  *  See identifier-handling.rst for more details on the identifier algorithms
79844  *  and the internal representation.  See function-objects.rst for details on
79845  *  what function templates and instances are expected to look like.
79846  *
79847  *  Care must be taken to avoid duk_tval pointer invalidation caused by
79848  *  e.g. value stack or object resizing.
79849  *
79850  *  TODO: properties for function instances could be initialized much more
79851  *  efficiently by creating a property allocation for a certain size and
79852  *  filling in keys and values directly (and INCREFing both with "bulk incref"
79853  *  primitives.
79854  *
79855  *  XXX: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit
79856  *  awkward (especially because they follow the prototype chain); rework
79857  *  if "raw" own property helpers are added.
79858  */
79859
79860 /* #include duk_internal.h -> already included */
79861
79862 /*
79863  *  Local result type for duk__get_identifier_reference() lookup.
79864  */
79865
79866 typedef struct {
79867         duk_hobject *env;
79868         duk_hobject *holder;      /* for object-bound identifiers */
79869         duk_tval *value;          /* for register-bound and declarative env identifiers */
79870         duk_uint_t attrs;         /* property attributes for identifier (relevant if value != NULL) */
79871         duk_bool_t has_this;      /* for object-bound identifiers: provide 'this' binding */
79872 } duk__id_lookup_result;
79873
79874 /*
79875  *  Create a new function object based on a "template function" which contains
79876  *  compiled bytecode, constants, etc, but lacks a lexical environment.
79877  *
79878  *  ECMAScript requires that each created closure is a separate object, with
79879  *  its own set of editable properties.  However, structured property values
79880  *  (such as the formal arguments list and the variable map) are shared.
79881  *  Also the bytecode, constants, and inner functions are shared.
79882  *
79883  *  See E5 Section 13.2 for detailed requirements on the function objects;
79884  *  there are no similar requirements for function "templates" which are an
79885  *  implementation dependent internal feature.  Also see function-objects.rst
79886  *  for a discussion on the function instance properties provided by this
79887  *  implementation.
79888  *
79889  *  Notes:
79890  *
79891  *   * Order of internal properties should match frequency of use, since the
79892  *     properties will be linearly scanned on lookup (functions usually don't
79893  *     have enough properties to warrant a hash part).
79894  *
79895  *   * The created closure is independent of its template; they do share the
79896  *     same 'data' buffer object, but the template object itself can be freed
79897  *     even if the closure object remains reachable.
79898  */
79899
79900 DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompfunc *f) {
79901         duk_tval *tv, *tv_end;
79902         duk_hobject **funcs, **funcs_end;
79903
79904         DUK_UNREF(thr);
79905
79906         /* If function creation fails due to out-of-memory, the data buffer
79907          * pointer may be NULL in some cases.  That's actually possible for
79908          * GC code, but shouldn't be possible here because the incomplete
79909          * function will be unwound from the value stack and never instantiated.
79910          */
79911         DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL);
79912
79913         tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f);
79914         tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, f);
79915         while (tv < tv_end) {
79916                 DUK_TVAL_INCREF(thr, tv);
79917                 tv++;
79918         }
79919
79920         funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, f);
79921         funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f);
79922         while (funcs < funcs_end) {
79923                 DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs);
79924                 funcs++;
79925         }
79926 }
79927
79928 /* Push a new closure on the stack.
79929  *
79930  * Note: if fun_temp has NEWENV, i.e. a new lexical and variable declaration
79931  * is created when the function is called, only outer_lex_env matters
79932  * (outer_var_env is ignored and may or may not be same as outer_lex_env).
79933  */
79934
79935 DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = {
79936         /* order: most frequent to least frequent */
79937         DUK_STRIDX_INT_VARMAP,
79938         DUK_STRIDX_INT_FORMALS,
79939 #if defined(DUK_USE_PC2LINE)
79940         DUK_STRIDX_INT_PC2LINE,
79941 #endif
79942 #if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
79943         DUK_STRIDX_FILE_NAME,
79944 #endif
79945 #if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
79946         DUK_STRIDX_INT_SOURCE
79947 #endif
79948 };
79949
79950 DUK_INTERNAL
79951 void duk_js_push_closure(duk_hthread *thr,
79952                          duk_hcompfunc *fun_temp,
79953                          duk_hobject *outer_var_env,
79954                          duk_hobject *outer_lex_env,
79955                          duk_bool_t add_auto_proto) {
79956         duk_hcompfunc *fun_clos;
79957         duk_small_uint_t i;
79958         duk_uint_t len_value;
79959
79960         DUK_ASSERT(fun_temp != NULL);
79961         DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp) != NULL);
79962         DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp) != NULL);
79963         DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp) != NULL);
79964         DUK_ASSERT(outer_var_env != NULL);
79965         DUK_ASSERT(outer_lex_env != NULL);
79966         DUK_UNREF(len_value);
79967
79968         fun_clos = duk_push_hcompfunc(thr);
79969         DUK_ASSERT(fun_clos != NULL);
79970         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) fun_clos) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
79971
79972         duk_push_hobject(thr, &fun_temp->obj);  /* -> [ ... closure template ] */
79973
79974         DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun_clos));
79975         DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) == NULL);
79976         DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) == NULL);
79977         DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) == NULL);
79978
79979         DUK_HCOMPFUNC_SET_DATA(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp));
79980         DUK_HCOMPFUNC_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp));
79981         DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp));
79982
79983         /* Note: all references inside 'data' need to get their refcounts
79984          * upped too.  This is the case because refcounts are decreased
79985          * through every function referencing 'data' independently.
79986          */
79987
79988         DUK_HBUFFER_INCREF(thr, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos));
79989         duk__inc_data_inner_refcounts(thr, fun_temp);
79990
79991         fun_clos->nregs = fun_temp->nregs;
79992         fun_clos->nargs = fun_temp->nargs;
79993 #if defined(DUK_USE_DEBUGGER_SUPPORT)
79994         fun_clos->start_line = fun_temp->start_line;
79995         fun_clos->end_line = fun_temp->end_line;
79996 #endif
79997
79998         DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) != NULL);
79999         DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) != NULL);
80000         DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) != NULL);
80001
80002         /* XXX: Could also copy from template, but there's no way to have any
80003          * other value here now (used code has no access to the template).
80004          * Prototype is set by duk_push_hcompfunc().
80005          */
80006         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
80007 #if 0
80008         DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
80009 #endif
80010
80011         /* Copy duk_hobject flags as is from the template using a mask.
80012          * Leave out duk_heaphdr owned flags just in case (e.g. if there's
80013          * some GC flag or similar).  Some flags can then be adjusted
80014          * separately if necessary.
80015          */
80016
80017         /* DUK_HEAPHDR_SET_FLAGS() masks changes to non-duk_heaphdr flags only. */
80018         DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) fun_clos, DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp));
80019         DUK_DD(DUK_DDPRINT("fun_temp heaphdr flags: 0x%08lx, fun_clos heaphdr flags: 0x%08lx",
80020                            (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp),
80021                            (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_clos)));
80022
80023         DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
80024         DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj));
80025         DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj));
80026         DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj));
80027         DUK_ASSERT(!DUK_HOBJECT_IS_THREAD(&fun_clos->obj));
80028         /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
80029         /* DUK_HOBJECT_FLAG_NEWENV: handled below */
80030         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj));
80031         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj));
80032         DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj));
80033
80034         if (!DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj)) {
80035                 /* If the template is not constructable don't add an automatic
80036                  * .prototype property.  This is the case for e.g. ES2015 object
80037                  * literal getters/setters and method definitions.
80038                  */
80039                 add_auto_proto = 0;
80040         }
80041
80042         /*
80043          *  Setup environment record properties based on the template and
80044          *  its flags.
80045          *
80046          *  If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
80047          *  records represent identifiers "outside" the function; the
80048          *  "inner" environment records are created on demand.  Otherwise,
80049          *  the environment records are those that will be directly used
80050          *  (e.g. for declarations).
80051          *
80052          *  _Lexenv is always set; _Varenv defaults to _Lexenv if missing,
80053          *  so _Varenv is only set if _Lexenv != _Varenv.
80054          *
80055          *  This is relatively complex, see doc/identifier-handling.rst.
80056          */
80057
80058         if (DUK_HOBJECT_HAS_NEWENV(&fun_clos->obj)) {
80059 #if defined(DUK_USE_FUNC_NAME_PROPERTY)
80060                 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) {
80061                         duk_hobject *proto;
80062                         duk_hdecenv *new_env;
80063
80064                         /*
80065                          *  Named function expression, name needs to be bound
80066                          *  in an intermediate environment record.  The "outer"
80067                          *  lexical/variable environment will thus be:
80068                          *
80069                          *  a) { funcname: <func>, __prototype: outer_lex_env }
80070                          *  b) { funcname: <func>, __prototype:  <globalenv> }  (if outer_lex_env missing)
80071                          */
80072
80073                         if (outer_lex_env) {
80074                                 proto = outer_lex_env;
80075                         } else {
80076                                 proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
80077                         }
80078
80079                         /* -> [ ... closure template env ] */
80080                         new_env = duk_hdecenv_alloc(thr,
80081                                                     DUK_HOBJECT_FLAG_EXTENSIBLE |
80082                                                     DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
80083                         DUK_ASSERT(new_env != NULL);
80084                         duk_push_hobject(thr, (duk_hobject *) new_env);
80085
80086                         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) new_env) == NULL);
80087                         DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) new_env, proto);
80088                         DUK_HOBJECT_INCREF_ALLOWNULL(thr, proto);
80089
80090                         DUK_ASSERT(new_env->thread == NULL);  /* Closed. */
80091                         DUK_ASSERT(new_env->varmap == NULL);
80092
80093                         /* It's important that duk_xdef_prop() is a 'raw define' so that any
80094                          * properties in an ancestor are never an issue (they should never be
80095                          * e.g. non-writable, but just in case).
80096                          *
80097                          * Because template objects are not visible to user code, the case
80098                          * where .name is missing shouldn't happen in practice.  It it does,
80099                          * the name 'undefined' gets bound and maps to the closure (which is
80100                          * a bit odd, but safe).
80101                          */
80102                         (void) duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_NAME);
80103                         /* -> [ ... closure template env funcname ] */
80104                         duk_dup_m4(thr);                                           /* -> [ ... closure template env funcname closure ] */
80105                         duk_xdef_prop(thr, -3, DUK_PROPDESC_FLAGS_NONE);           /* -> [ ... closure template env ] */
80106                         /* env[funcname] = closure */
80107
80108                         /* [ ... closure template env ] */
80109
80110                         DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, (duk_hobject *) new_env);
80111                         DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, (duk_hobject *) new_env);
80112                         DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);
80113                         DUK_HOBJECT_INCREF(thr, (duk_hobject *) new_env);
80114                         duk_pop_unsafe(thr);
80115
80116                         /* [ ... closure template ] */
80117                 }
80118                 else
80119 #endif  /* DUK_USE_FUNC_NAME_PROPERTY */
80120                 {
80121                         /*
80122                          *  Other cases (function declaration, anonymous function expression,
80123                          *  strict direct eval code).  The "outer" environment will be whatever
80124                          *  the caller gave us.
80125                          */
80126
80127                         DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env);
80128                         DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_lex_env);
80129                         DUK_HOBJECT_INCREF(thr, outer_lex_env);
80130                         DUK_HOBJECT_INCREF(thr, outer_lex_env);
80131
80132                         /* [ ... closure template ] */
80133                 }
80134         } else {
80135                 /*
80136                  *  Function gets no new environment when called.  This is the
80137                  *  case for global code, indirect eval code, and non-strict
80138                  *  direct eval code.  There is no direct correspondence to the
80139                  *  E5 specification, as global/eval code is not exposed as a
80140                  *  function.
80141                  */
80142
80143                 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj));
80144
80145                 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env);
80146                 DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_var_env);
80147                 DUK_HOBJECT_INCREF(thr, outer_lex_env);  /* NULLs not allowed; asserted on entry */
80148                 DUK_HOBJECT_INCREF(thr, outer_var_env);
80149         }
80150         DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipO, lexenv -> %!ipO",
80151                              (duk_heaphdr *) fun_clos->var_env,
80152                              (duk_heaphdr *) fun_clos->lex_env));
80153
80154         /* Call handling assumes this for all callable closures. */
80155         DUK_ASSERT(DUK_HCOMPFUNC_GET_LEXENV(thr->heap, fun_clos) != NULL);
80156         DUK_ASSERT(DUK_HCOMPFUNC_GET_VARENV(thr->heap, fun_clos) != NULL);
80157
80158         /*
80159          *  Copy some internal properties directly
80160          *
80161          *  The properties will be non-writable and non-enumerable, but
80162          *  configurable.
80163          */
80164
80165         /* [ ... closure template ] */
80166
80167         DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
80168                              (duk_tval *) duk_get_tval(thr, -2),
80169                              (duk_tval *) duk_get_tval(thr, -1)));
80170
80171         for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
80172                 duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i];
80173                 if (duk_get_prop_stridx_short(thr, -1, stridx)) {
80174                         /* [ ... closure template val ] */
80175                         DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
80176                         duk_xdef_prop_stridx_short(thr, -3, stridx, DUK_PROPDESC_FLAGS_C);
80177                 } else {
80178                         DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
80179                         duk_pop_unsafe(thr);
80180                 }
80181         }
80182
80183         /*
80184          *  "length" maps to number of formals (E5 Section 13.2) for function
80185          *  declarations/expressions (non-bound functions).  Note that 'nargs'
80186          *  is NOT necessarily equal to the number of arguments.  Use length
80187          *  of _Formals; if missing, assume nargs matches .length.
80188          */
80189
80190         /* [ ... closure template ] */
80191
80192         /* XXX: these lookups should be just own property lookups instead of
80193          * looking up the inheritance chain.
80194          */
80195         if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_INT_FORMALS)) {
80196                 /* [ ... closure template formals ] */
80197                 len_value = (duk_uint_t) duk_get_length(thr, -1);  /* could access duk_harray directly, not important */
80198                 DUK_DD(DUK_DDPRINT("closure length from _Formals -> %ld", (long) len_value));
80199         } else {
80200                 len_value = fun_temp->nargs;
80201                 DUK_DD(DUK_DDPRINT("closure length defaulted from nargs -> %ld", (long) len_value));
80202         }
80203         duk_pop_unsafe(thr);
80204
80205         duk_push_uint(thr, len_value);  /* [ ... closure template len_value ] */
80206         duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
80207
80208         /*
80209          *  "prototype" is, by default, a fresh object with the "constructor"
80210          *  property.
80211          *
80212          *  Note that this creates a circular reference for every function
80213          *  instance (closure) which prevents refcount-based collection of
80214          *  function instances.
80215          *
80216          *  XXX: Try to avoid creating the default prototype object, because
80217          *  many functions are not used as constructors and the default
80218          *  prototype is unnecessary.  Perhaps it could be created on-demand
80219          *  when it is first accessed?
80220          */
80221
80222         /* [ ... closure template ] */
80223
80224         if (add_auto_proto) {
80225                 duk_push_object(thr);  /* -> [ ... closure template newobj ] */
80226                 duk_dup_m3(thr);       /* -> [ ... closure template newobj closure ] */
80227                 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC);  /* -> [ ... closure template newobj ] */
80228                 duk_compact(thr, -1);  /* compact the prototype */
80229                 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);     /* -> [ ... closure template ] */
80230         }
80231
80232         /*
80233          *  "arguments" and "caller" must be mapped to throwers for strict
80234          *  mode and bound functions (E5 Section 15.3.5).
80235          *
80236          *  XXX: This is expensive to have for every strict function instance.
80237          *  Try to implement as virtual properties or on-demand created properties.
80238          */
80239
80240         /* [ ... closure template ] */
80241
80242         if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
80243                 duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_CALLER);
80244                 duk_xdef_prop_stridx_thrower(thr, -2, DUK_STRIDX_LC_ARGUMENTS);
80245         } else {
80246 #if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
80247                 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
80248                 duk_push_null(thr);
80249                 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
80250 #else
80251                 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
80252 #endif
80253         }
80254
80255         /*
80256          *  "name" used to be non-standard but is now defined by ES2015.
80257          *  In ES2015/ES2016 the .name property is configurable.
80258          */
80259
80260         /* [ ... closure template ] */
80261
80262 #if defined(DUK_USE_FUNC_NAME_PROPERTY)
80263         /* XXX: Look for own property only; doesn't matter much because
80264          * templates are bare objects.
80265          */
80266         if (duk_get_prop_stridx_short(thr, -1, DUK_STRIDX_NAME)) {
80267                 /* [ ... closure template name ] */
80268                 DUK_ASSERT(duk_is_string(thr, -1));
80269                 DUK_DD(DUK_DDPRINT("setting function instance name to %!T", duk_get_tval(thr, -1)));
80270                 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);  /* -> [ ... closure template ] */
80271         } else {
80272                 /* Anonymous functions don't have a .name in ES2015, so don't set
80273                  * it on the instance either.  The instance will then inherit
80274                  * it from Function.prototype.name.
80275                  */
80276                 DUK_DD(DUK_DDPRINT("not setting function instance .name"));
80277                 duk_pop_unsafe(thr);
80278         }
80279 #endif
80280
80281         /*
80282          *  Compact the closure, in most cases no properties will be added later.
80283          *  Also, without this the closures end up having unused property slots
80284          *  (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
80285          *  A better future solution would be to allocate the closure directly
80286          *  to correct size (and setup the properties directly without going
80287          *  through the API).
80288          */
80289
80290         duk_compact(thr, -2);
80291
80292         /*
80293          *  Some assertions (E5 Section 13.2).
80294          */
80295
80296         DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
80297         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
80298         DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
80299         DUK_ASSERT(duk_has_prop_stridx(thr, -2, DUK_STRIDX_LENGTH) != 0);
80300         DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(thr, -2, DUK_STRIDX_PROTOTYPE) != 0);
80301         /* May be missing .name */
80302         DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
80303                    duk_has_prop_stridx(thr, -2, DUK_STRIDX_CALLER) != 0);
80304         DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
80305                    duk_has_prop_stridx(thr, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
80306
80307         /*
80308          *  Finish
80309          */
80310
80311         /* [ ... closure template ] */
80312
80313         DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
80314                              (duk_tval *) duk_get_tval(thr, -1),
80315                              (duk_tval *) duk_get_tval(thr, -2)));
80316
80317         duk_pop_unsafe(thr);
80318
80319         /* [ ... closure ] */
80320 }
80321
80322 /*
80323  *  Delayed activation environment record initialization (for functions
80324  *  with NEWENV).
80325  *
80326  *  The non-delayed initialization is handled by duk_handle_call().
80327  */
80328
80329 /* shared helper */
80330 DUK_INTERNAL
80331 duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
80332                                                       duk_hobject *func,
80333                                                       duk_size_t bottom_byteoff) {
80334         duk_hdecenv *env;
80335         duk_hobject *parent;
80336         duk_hcompfunc *f;
80337
80338         DUK_ASSERT(thr != NULL);
80339         DUK_ASSERT(func != NULL);
80340
80341         f = (duk_hcompfunc *) func;
80342         parent = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
80343         if (!parent) {
80344                 parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
80345         }
80346
80347         env = duk_hdecenv_alloc(thr,
80348                                 DUK_HOBJECT_FLAG_EXTENSIBLE |
80349                                 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV));
80350         DUK_ASSERT(env != NULL);
80351         duk_push_hobject(thr, (duk_hobject *) env);
80352
80353         DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) env) == NULL);
80354         DUK_HOBJECT_SET_PROTOTYPE(thr->heap, (duk_hobject *) env, parent);
80355         DUK_HOBJECT_INCREF_ALLOWNULL(thr, parent);  /* parent env is the prototype */
80356
80357         /* open scope information, for compiled functions only */
80358
80359         DUK_ASSERT(env->thread == NULL);
80360         DUK_ASSERT(env->varmap == NULL);
80361         DUK_ASSERT(env->regbase_byteoff == 0);
80362         if (DUK_HOBJECT_IS_COMPFUNC(func)) {
80363                 duk_hobject *varmap;
80364                 duk_tval *tv;
80365
80366                 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
80367                 if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
80368                         DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
80369                         varmap = DUK_TVAL_GET_OBJECT(tv);
80370                         DUK_ASSERT(varmap != NULL);
80371                         env->varmap = varmap;
80372                         DUK_HOBJECT_INCREF(thr, varmap);
80373                         env->thread = thr;
80374                         DUK_HTHREAD_INCREF(thr, thr);
80375                         env->regbase_byteoff = bottom_byteoff;
80376                 } else {
80377                         /* If function has no _Varmap, leave the environment closed. */
80378                         DUK_ASSERT(env->thread == NULL);
80379                         DUK_ASSERT(env->varmap == NULL);
80380                         DUK_ASSERT(env->regbase_byteoff == 0);
80381                 }
80382         }
80383
80384         return (duk_hobject *) env;
80385 }
80386
80387 DUK_INTERNAL
80388 void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
80389                                                         duk_activation *act) {
80390         duk_hobject *func;
80391         duk_hobject *env;
80392
80393         DUK_ASSERT(thr != NULL);
80394         func = DUK_ACT_GET_FUNC(act);
80395         DUK_ASSERT(func != NULL);
80396         DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));  /* bound functions are never in act 'func' */
80397
80398         /*
80399          *  Delayed initialization only occurs for 'NEWENV' functions.
80400          */
80401
80402         DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
80403         DUK_ASSERT(act->lex_env == NULL);
80404         DUK_ASSERT(act->var_env == NULL);
80405
80406         env = duk_create_activation_environment_record(thr, func, act->bottom_byteoff);
80407         DUK_ASSERT(env != NULL);
80408         /* 'act' is a stable pointer, so still OK. */
80409
80410         DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
80411 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
80412         {
80413                 duk_hobject *p = env;
80414                 while (p) {
80415                         DUK_DDD(DUK_DDDPRINT("  -> %!ipO", (duk_heaphdr *) p));
80416                         p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p);
80417                 }
80418         }
80419 #endif
80420
80421         act->lex_env = env;
80422         act->var_env = env;
80423         DUK_HOBJECT_INCREF(thr, env);  /* XXX: incref by count (here 2 times) */
80424         DUK_HOBJECT_INCREF(thr, env);
80425
80426         duk_pop_unsafe(thr);
80427 }
80428
80429 /*
80430  *  Closing environment records.
80431  *
80432  *  The environment record MUST be closed with the thread where its activation
80433  *  is; i.e. if 'env' is open, 'thr' must match env->thread, and the regbase
80434  *  and varmap must still be valid.  On entry, 'env' must be reachable.
80435  */
80436
80437 DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env) {
80438         duk_uint_fast32_t i;
80439         duk_hobject *varmap;
80440         duk_hstring *key;
80441         duk_tval *tv;
80442         duk_uint_t regnum;
80443
80444         DUK_ASSERT(thr != NULL);
80445         DUK_ASSERT(env != NULL);
80446
80447         if (DUK_UNLIKELY(!DUK_HOBJECT_IS_DECENV(env))) {
80448                 DUK_DDD(DUK_DDDPRINT("env not a declarative record: %!iO", (duk_heaphdr *) env));
80449                 return;
80450         }
80451
80452         varmap = ((duk_hdecenv *) env)->varmap;
80453         if (varmap == NULL) {
80454                 DUK_DDD(DUK_DDDPRINT("env already closed: %!iO", (duk_heaphdr *) env));
80455
80456                 return;
80457         }
80458         DUK_ASSERT(((duk_hdecenv *) env)->thread != NULL);
80459         DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env);
80460
80461         DUK_DDD(DUK_DDDPRINT("closing env: %!iO", (duk_heaphdr *) env));
80462         DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
80463
80464         /* Env must be closed in the same thread as where it runs. */
80465         DUK_ASSERT(((duk_hdecenv *) env)->thread == thr);
80466
80467         /* XXX: additional conditions when to close variables? we don't want to do it
80468          * unless the environment may have "escaped" (referenced in a function closure).
80469          * With delayed environments, the existence is probably good enough of a check.
80470          */
80471
80472         /* Note: we rely on the _Varmap having a bunch of nice properties, like:
80473          *  - being compacted and unmodified during this process
80474          *  - not containing an array part
80475          *  - having correct value types
80476          */
80477
80478         DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
80479
80480         /* Copy over current variable values from value stack to the
80481          * environment record.  The scope object is empty but may
80482          * inherit from another scope which has conflicting names.
80483          */
80484
80485         /* XXX: Do this using a once allocated entry area, no side effects.
80486          * Hash part would need special treatment however (maybe copy, and
80487          * then realloc with hash part if large enough).
80488          */
80489         for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
80490                 duk_size_t regbase_byteoff;
80491
80492                 key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
80493                 DUK_ASSERT(key != NULL);   /* assume keys are compact in _Varmap */
80494                 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i));  /* assume plain values */
80495
80496                 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
80497                 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
80498                 DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX);  /* limits */
80499 #if defined(DUK_USE_FASTINT)
80500                 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
80501                 regnum = (duk_uint_t) DUK_TVAL_GET_FASTINT_U32(tv);
80502 #else
80503                 regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
80504 #endif
80505
80506                 regbase_byteoff = ((duk_hdecenv *) env)->regbase_byteoff;
80507                 DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum >= (duk_uint8_t *) thr->valstack);
80508                 DUK_ASSERT((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum < (duk_uint8_t *) thr->valstack_top);
80509
80510                 /* If property already exists, overwrites silently.
80511                  * Property is writable, but not deletable (not configurable
80512                  * in terms of property attributes).
80513                  */
80514                 duk_push_tval(thr, (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + regbase_byteoff + sizeof(duk_tval) * regnum));
80515                 DUK_DDD(DUK_DDDPRINT("closing identifier %!O -> reg %ld, value %!T",
80516                                      (duk_heaphdr *) key,
80517                                      (long) regnum,
80518                                      (duk_tval *) duk_get_tval(thr, -1)));
80519                 duk_hobject_define_property_internal(thr, env, key, DUK_PROPDESC_FLAGS_WE);
80520         }
80521
80522         /* NULL atomically to avoid inconsistent state + side effects. */
80523         DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->thread);
80524         DUK_HOBJECT_DECREF_NORZ(thr, ((duk_hdecenv *) env)->varmap);
80525         ((duk_hdecenv *) env)->thread = NULL;
80526         ((duk_hdecenv *) env)->varmap = NULL;
80527
80528         DUK_DDD(DUK_DDDPRINT("env after closing: %!O", (duk_heaphdr *) env));
80529 }
80530
80531 /*
80532  *  GETIDREF: a GetIdentifierReference-like helper.
80533  *
80534  *  Provides a parent traversing lookup and a single level lookup
80535  *  (for HasBinding).
80536  *
80537  *  Instead of returning the value, returns a bunch of values allowing
80538  *  the caller to read, write, or delete the binding.  Value pointers
80539  *  are duk_tval pointers which can be mutated directly as long as
80540  *  refcounts are properly updated.  Note that any operation which may
80541  *  reallocate valstacks or compact objects may invalidate the returned
80542  *  duk_tval (but not object) pointers, so caller must be very careful.
80543  *
80544  *  If starting environment record 'env' is given, 'act' is ignored.
80545  *  However, if 'env' is NULL, the caller may identify, in 'act', an
80546  *  activation which hasn't had its declarative environment initialized
80547  *  yet.  The activation registers are then looked up, and its parent
80548  *  traversed normally.
80549  *
80550  *  The 'out' structure values are only valid if the function returns
80551  *  success (non-zero).
80552  */
80553
80554 /* lookup name from an open declarative record's registers */
80555 DUK_LOCAL
80556 duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
80557                                          duk_hstring *name,
80558                                          duk_hdecenv *env,
80559                                          duk__id_lookup_result *out) {
80560         duk_tval *tv;
80561         duk_size_t reg_rel;
80562
80563         DUK_ASSERT(thr != NULL);
80564         DUK_ASSERT(name != NULL);
80565         DUK_ASSERT(env != NULL);
80566         DUK_ASSERT(out != NULL);
80567
80568         DUK_ASSERT(DUK_HOBJECT_IS_DECENV((duk_hobject *) env));
80569         DUK_ASSERT_HDECENV_VALID(env);
80570
80571         if (env->thread == NULL) {
80572                 /* already closed */
80573                 return 0;
80574         }
80575         DUK_ASSERT(env->varmap != NULL);
80576
80577         tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env->varmap, name);
80578         if (DUK_UNLIKELY(tv == NULL)) {
80579                 return 0;
80580         }
80581
80582         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
80583         DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (duk_double_t) DUK_UINT32_MAX);  /* limits */
80584 #if defined(DUK_USE_FASTINT)
80585         DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
80586         reg_rel = (duk_size_t) DUK_TVAL_GET_FASTINT_U32(tv);
80587 #else
80588         reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
80589 #endif
80590         DUK_ASSERT_DISABLE(reg_rel >= 0);  /* unsigned */
80591
80592         tv = (duk_tval *) (void *) ((duk_uint8_t *) env->thread->valstack + env->regbase_byteoff + sizeof(duk_tval) * reg_rel);
80593         DUK_ASSERT(tv >= env->thread->valstack && tv < env->thread->valstack_end);  /* XXX: more accurate? */
80594
80595         out->value = tv;
80596         out->attrs = DUK_PROPDESC_FLAGS_W;  /* registers are mutable, non-deletable */
80597         out->env = (duk_hobject *) env;
80598         out->holder = NULL;
80599         out->has_this = 0;
80600         return 1;
80601 }
80602
80603 /* lookup name from current activation record's functions' registers */
80604 DUK_LOCAL
80605 duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
80606                                       duk_hstring *name,
80607                                       duk_activation *act,
80608                                       duk__id_lookup_result *out) {
80609         duk_tval *tv;
80610         duk_hobject *func;
80611         duk_hobject *varmap;
80612         duk_size_t reg_rel;
80613
80614         DUK_ASSERT(thr != NULL);
80615         DUK_ASSERT(name != NULL);
80616         DUK_ASSERT(act != NULL);
80617         DUK_ASSERT(out != NULL);
80618
80619         func = DUK_ACT_GET_FUNC(act);
80620         DUK_ASSERT(func != NULL);
80621         DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
80622
80623         if (!DUK_HOBJECT_IS_COMPFUNC(func)) {
80624                 return 0;
80625         }
80626
80627         /* XXX: move varmap to duk_hcompfunc struct field. */
80628         tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
80629         if (!tv) {
80630                 return 0;
80631         }
80632         DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
80633         varmap = DUK_TVAL_GET_OBJECT(tv);
80634         DUK_ASSERT(varmap != NULL);
80635
80636         tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
80637         if (!tv) {
80638                 return 0;
80639         }
80640         DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
80641         reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
80642         DUK_ASSERT_DISABLE(reg_rel >= 0);
80643         DUK_ASSERT(reg_rel < ((duk_hcompfunc *) func)->nregs);
80644
80645         tv = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + act->bottom_byteoff);
80646         tv += reg_rel;
80647
80648         out->value = tv;
80649         out->attrs = DUK_PROPDESC_FLAGS_W;  /* registers are mutable, non-deletable */
80650         out->env = NULL;
80651         out->holder = NULL;
80652         out->has_this = 0;
80653         return 1;
80654 }
80655
80656 DUK_LOCAL
80657 duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
80658                                          duk_hobject *env,
80659                                          duk_hstring *name,
80660                                          duk_activation *act,
80661                                          duk_bool_t parents,
80662                                          duk__id_lookup_result *out) {
80663         duk_tval *tv;
80664         duk_uint_t sanity;
80665
80666         DUK_ASSERT(thr != NULL);
80667         DUK_ASSERT(env != NULL || act != NULL);
80668         DUK_ASSERT(name != NULL);
80669         DUK_ASSERT(out != NULL);
80670
80671         DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env));
80672         DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env));
80673
80674         /*
80675          *  Conceptually, we look for the identifier binding by starting from
80676          *  'env' and following to chain of environment records (represented
80677          *  by the prototype chain).
80678          *
80679          *  If 'env' is NULL, the current activation does not yet have an
80680          *  allocated declarative environment record; this should be treated
80681          *  exactly as if the environment record existed but had no bindings
80682          *  other than register bindings.
80683          *
80684          *  Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared
80685          *  the environment will always be initialized immediately; hence
80686          *  a NULL 'env' should only happen with the flag set.  This is the
80687          *  case for: (1) function calls, and (2) strict, direct eval calls.
80688          */
80689
80690         if (env == NULL && act != NULL) {
80691                 duk_hobject *func;
80692                 duk_hcompfunc *f;
80693
80694                 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
80695                                      "delayed env case, look up activation regs first"));
80696
80697                 /*
80698                  *  Try registers
80699                  */
80700
80701                 if (duk__getid_activation_regs(thr, name, act, out)) {
80702                         DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
80703                                              "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
80704                                              "(found from register bindings when env=NULL)",
80705                                              (duk_heaphdr *) name, (duk_tval *) out->value,
80706                                              (long) out->attrs, (long) out->has_this,
80707                                              (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
80708                         return 1;
80709                 }
80710
80711                 DUK_DDD(DUK_DDDPRINT("not found in current activation regs"));
80712
80713                 /*
80714                  *  Not found in registers, proceed to the parent record.
80715                  *  Here we need to determine what the parent would be,
80716                  *  if 'env' was not NULL (i.e. same logic as when initializing
80717                  *  the record).
80718                  *
80719                  *  Note that environment initialization is only deferred when
80720                  *  DUK_HOBJECT_HAS_NEWENV is set, and this only happens for:
80721                  *    - Function code
80722                  *    - Strict eval code
80723                  *
80724                  *  We only need to check _Lexenv here; _Varenv exists only if it
80725                  *  differs from _Lexenv (and thus _Lexenv will also be present).
80726                  */
80727
80728                 if (!parents) {
80729                         DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
80730                                              "(not found from register bindings when env=NULL)"));
80731                         goto fail_not_found;
80732                 }
80733
80734                 func = DUK_ACT_GET_FUNC(act);
80735                 DUK_ASSERT(func != NULL);
80736                 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
80737                 f = (duk_hcompfunc *) func;
80738
80739                 env = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
80740                 if (!env) {
80741                         env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
80742                 }
80743
80744                 DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO",
80745                                      (duk_heaphdr *) env));
80746         }
80747
80748         /*
80749          *  Prototype walking starting from 'env'.
80750          *
80751          *  ('act' is not needed anywhere here.)
80752          */
80753
80754         sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
80755         while (env != NULL) {
80756                 duk_small_uint_t cl;
80757                 duk_uint_t attrs;
80758
80759                 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
80760                                      (duk_heaphdr *) name,
80761                                      (void *) env,
80762                                      (duk_heaphdr *) env));
80763
80764                 DUK_ASSERT(env != NULL);
80765                 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
80766                 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
80767
80768                 cl = DUK_HOBJECT_GET_CLASS_NUMBER(env);
80769                 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV);
80770                 if (cl == DUK_HOBJECT_CLASS_DECENV) {
80771                         /*
80772                          *  Declarative environment record.
80773                          *
80774                          *  Identifiers can never be stored in ancestors and are
80775                          *  always plain values, so we can use an internal helper
80776                          *  and access the value directly with an duk_tval ptr.
80777                          *
80778                          *  A closed environment is only indicated by it missing
80779                          *  the "book-keeping" properties required for accessing
80780                          *  register-bound variables.
80781                          */
80782
80783                         DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env);
80784                         if (duk__getid_open_decl_env_regs(thr, name, (duk_hdecenv *) env, out)) {
80785                                 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
80786                                                      "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
80787                                                      "(declarative environment record, scope open, found in regs)",
80788                                                      (duk_heaphdr *) name, (duk_tval *) out->value,
80789                                                      (long) out->attrs, (long) out->has_this,
80790                                                      (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
80791                                 return 1;
80792                         }
80793
80794                         tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs);
80795                         if (tv) {
80796                                 out->value = tv;
80797                                 out->attrs = attrs;
80798                                 out->env = env;
80799                                 out->holder = env;
80800                                 out->has_this = 0;
80801
80802                                 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
80803                                                      "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
80804                                                      "(declarative environment record, found in properties)",
80805                                                      (duk_heaphdr *) name, (duk_tval *) out->value,
80806                                                      (long) out->attrs, (long) out->has_this,
80807                                                      (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
80808                                 return 1;
80809                         }
80810                 } else {
80811                         /*
80812                          *  Object environment record.
80813                          *
80814                          *  Binding (target) object is an external, uncontrolled object.
80815                          *  Identifier may be bound in an ancestor property, and may be
80816                          *  an accessor.  Target can also be a Proxy which we must support
80817                          *  here.
80818                          */
80819
80820                         /* XXX: we could save space by using _Target OR _This.  If _Target, assume
80821                          * this binding is undefined.  If _This, assumes this binding is _This, and
80822                          * target is also _This.  One property would then be enough.
80823                          */
80824
80825                         duk_hobject *target;
80826                         duk_bool_t found;
80827
80828                         DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV);
80829                         DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env);
80830
80831                         target = ((duk_hobjenv *) env)->target;
80832                         DUK_ASSERT(target != NULL);
80833
80834                         /* Target may be a Proxy or property may be an accessor, so we must
80835                          * use an actual, Proxy-aware hasprop check here.
80836                          *
80837                          * out->holder is NOT set to the actual duk_hobject where the
80838                          * property is found, but rather the object binding target object.
80839                          */
80840
80841 #if defined(DUK_USE_ES6_PROXY)
80842                         if (DUK_UNLIKELY(DUK_HOBJECT_IS_PROXY(target))) {
80843                                 duk_tval tv_name;
80844                                 duk_tval tv_target_tmp;
80845
80846                                 DUK_ASSERT(name != NULL);
80847                                 DUK_TVAL_SET_STRING(&tv_name, name);
80848                                 DUK_TVAL_SET_OBJECT(&tv_target_tmp, target);
80849
80850                                 found = duk_hobject_hasprop(thr, &tv_target_tmp, &tv_name);
80851                         } else
80852 #endif  /* DUK_USE_ES6_PROXY */
80853                         {
80854                                 /* XXX: duk_hobject_hasprop() would be correct for
80855                                  * non-Proxy objects too, but it is about ~20-25%
80856                                  * slower at present so separate code paths for
80857                                  * Proxy and non-Proxy now.
80858                                  */
80859                                 found = duk_hobject_hasprop_raw(thr, target, name);
80860                         }
80861
80862                         if (found) {
80863                                 out->value = NULL;  /* can't get value, may be accessor */
80864                                 out->attrs = 0;     /* irrelevant when out->value == NULL */
80865                                 out->env = env;
80866                                 out->holder = target;
80867                                 out->has_this = ((duk_hobjenv *) env)->has_this;
80868
80869                                 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
80870                                                      "name=%!O -> value=%!T, attrs=%ld, has_this=%ld, env=%!O, holder=%!O "
80871                                                      "(object environment record)",
80872                                                      (duk_heaphdr *) name, (duk_tval *) out->value,
80873                                                      (long) out->attrs, (long) out->has_this,
80874                                                      (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
80875                                 return 1;
80876                         }
80877                 }
80878
80879                 if (!parents) {
80880                         DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
80881                                              "(not found from first traversed env)"));
80882                         goto fail_not_found;
80883                 }
80884
80885                 if (DUK_UNLIKELY(sanity-- == 0)) {
80886                         DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
80887                         DUK_WO_NORETURN(return 0;);
80888                 }
80889                 env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);
80890         }
80891
80892         /*
80893          *  Not found (even in global object)
80894          */
80895
80896  fail_not_found:
80897         return 0;
80898 }
80899
80900 /*
80901  *  HASVAR: check identifier binding from a given environment record
80902  *  without traversing its parents.
80903  *
80904  *  This primitive is not exposed to user code as such, but is used
80905  *  internally for e.g. declaration binding instantiation.
80906  *
80907  *  See E5 Sections:
80908  *    10.2.1.1.1 HasBinding(N)
80909  *    10.2.1.2.1 HasBinding(N)
80910  *
80911  *  Note: strictness has no bearing on this check.  Hence we don't take
80912  *  a 'strict' parameter.
80913  */
80914
80915 #if 0  /*unused*/
80916 DUK_INTERNAL
80917 duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr,
80918                                 duk_hobject *env,
80919                                 duk_hstring *name) {
80920         duk__id_lookup_result ref;
80921         duk_bool_t parents;
80922
80923         DUK_DDD(DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O "
80924                              "(env -> %!dO)",
80925                              (void *) thr, (void *) env, (duk_heaphdr *) name,
80926                              (duk_heaphdr *) env));
80927
80928         DUK_ASSERT(thr != NULL);
80929         DUK_ASSERT(env != NULL);
80930         DUK_ASSERT(name != NULL);
80931
80932         DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
80933         DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
80934
80935         DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
80936         DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
80937
80938         /* lookup results is ignored */
80939         parents = 0;
80940         return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref);
80941 }
80942 #endif
80943
80944 /*
80945  *  GETVAR
80946  *
80947  *  See E5 Sections:
80948  *    11.1.2 Identifier Reference
80949  *    10.3.1 Identifier Resolution
80950  *    11.13.1 Simple Assignment  [example of where the Reference is GetValue'd]
80951  *    8.7.1 GetValue (V)
80952  *    8.12.1 [[GetOwnProperty]] (P)
80953  *    8.12.2 [[GetProperty]] (P)
80954  *    8.12.3 [[Get]] (P)
80955  *
80956  *  If 'throw' is true, always leaves two values on top of stack: [val this].
80957  *
80958  *  If 'throw' is false, returns 0 if identifier cannot be resolved, and the
80959  *  stack will be unaffected in this case.  If identifier is resolved, returns
80960  *  1 and leaves [val this] on top of stack.
80961  *
80962  *  Note: the 'strict' flag of a reference returned by GetIdentifierReference
80963  *  is ignored by GetValue.  Hence we don't take a 'strict' parameter.
80964  *
80965  *  The 'throw' flag is needed for implementing 'typeof' for an unreferenced
80966  *  identifier.  An unreference identifier in other contexts generates a
80967  *  ReferenceError.
80968  */
80969
80970 DUK_LOCAL
80971 duk_bool_t duk__getvar_helper(duk_hthread *thr,
80972                               duk_hobject *env,
80973                               duk_activation *act,
80974                               duk_hstring *name,
80975                               duk_bool_t throw_flag) {
80976         duk__id_lookup_result ref;
80977         duk_tval tv_tmp_obj;
80978         duk_tval tv_tmp_key;
80979         duk_bool_t parents;
80980
80981         DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O "
80982                              "(env -> %!dO)",
80983                              (void *) thr, (void *) env, (void *) act,
80984                              (duk_heaphdr *) name, (duk_heaphdr *) env));
80985
80986         DUK_ASSERT(thr != NULL);
80987         DUK_ASSERT(name != NULL);
80988         /* env and act may be NULL */
80989
80990         DUK_STATS_INC(thr->heap, stats_getvar_all);
80991
80992         DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
80993         DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
80994
80995         parents = 1;     /* follow parent chain */
80996         if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
80997                 if (ref.value) {
80998                         duk_push_tval(thr, ref.value);
80999                         duk_push_undefined(thr);
81000                 } else {
81001                         DUK_ASSERT(ref.holder != NULL);
81002
81003                         /* ref.holder is safe across the getprop call (even
81004                          * with side effects) because 'env' is reachable and
81005                          * ref.holder is a direct heap pointer.
81006                          */
81007
81008                         DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
81009                         DUK_TVAL_SET_STRING(&tv_tmp_key, name);
81010                         (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key);  /* [value] */
81011
81012                         if (ref.has_this) {
81013                                 duk_push_hobject(thr, ref.holder);
81014                         } else {
81015                                 duk_push_undefined(thr);
81016                         }
81017
81018                         /* [value this] */
81019                 }
81020
81021                 return 1;
81022         } else {
81023                 if (throw_flag) {
81024                         DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
81025                                        "identifier '%s' undefined",
81026                                        (const char *) DUK_HSTRING_GET_DATA(name));
81027                         DUK_WO_NORETURN(return 0;);
81028                 }
81029
81030                 return 0;
81031         }
81032 }
81033
81034 DUK_INTERNAL
81035 duk_bool_t duk_js_getvar_envrec(duk_hthread *thr,
81036                                 duk_hobject *env,
81037                                 duk_hstring *name,
81038                                 duk_bool_t throw_flag) {
81039         return duk__getvar_helper(thr, env, NULL, name, throw_flag);
81040 }
81041
81042 DUK_INTERNAL
81043 duk_bool_t duk_js_getvar_activation(duk_hthread *thr,
81044                                     duk_activation *act,
81045                                     duk_hstring *name,
81046                                     duk_bool_t throw_flag) {
81047         DUK_ASSERT(act != NULL);
81048         return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag);
81049 }
81050
81051 /*
81052  *  PUTVAR
81053  *
81054  *  See E5 Sections:
81055  *    11.1.2 Identifier Reference
81056  *    10.3.1 Identifier Resolution
81057  *    11.13.1 Simple Assignment  [example of where the Reference is PutValue'd]
81058  *    8.7.2 PutValue (V,W)  [see especially step 3.b, undefined -> automatic global in non-strict mode]
81059  *    8.12.4 [[CanPut]] (P)
81060  *    8.12.5 [[Put]] (P)
81061  *
81062  *  Note: may invalidate any valstack (or object) duk_tval pointers because
81063  *  putting a value may reallocate any object or any valstack.  Caller beware.
81064  */
81065
81066 DUK_LOCAL
81067 void duk__putvar_helper(duk_hthread *thr,
81068                         duk_hobject *env,
81069                         duk_activation *act,
81070                         duk_hstring *name,
81071                         duk_tval *val,
81072                         duk_bool_t strict) {
81073         duk__id_lookup_result ref;
81074         duk_tval tv_tmp_obj;
81075         duk_tval tv_tmp_key;
81076         duk_bool_t parents;
81077
81078         DUK_STATS_INC(thr->heap, stats_putvar_all);
81079
81080         DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
81081                              "(env -> %!dO, val -> %!T)",
81082                              (void *) thr, (void *) env, (void *) act,
81083                              (duk_heaphdr *) name, (void *) val, (long) strict,
81084                              (duk_heaphdr *) env, (duk_tval *) val));
81085
81086         DUK_ASSERT(thr != NULL);
81087         DUK_ASSERT(name != NULL);
81088         DUK_ASSERT(val != NULL);
81089         /* env and act may be NULL */
81090
81091         DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
81092         DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
81093         DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val);
81094
81095         /*
81096          *  In strict mode E5 protects 'eval' and 'arguments' from being
81097          *  assigned to (or even declared anywhere).  Attempt to do so
81098          *  should result in a compile time SyntaxError.  See the internal
81099          *  design documentation for details.
81100          *
81101          *  Thus, we should never come here, run-time, for strict code,
81102          *  and name 'eval' or 'arguments'.
81103          */
81104
81105         DUK_ASSERT(!strict ||
81106                    (name != DUK_HTHREAD_STRING_EVAL(thr) &&
81107                     name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)));
81108
81109         /*
81110          *  Lookup variable and update in-place if found.
81111          */
81112
81113         parents = 1;     /* follow parent chain */
81114
81115         if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
81116                 if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
81117                         /* Update duk_tval in-place if pointer provided and the
81118                          * property is writable.  If the property is not writable
81119                          * (immutable binding), use duk_hobject_putprop() which
81120                          * will respect mutability.
81121                          */
81122                         duk_tval *tv_val;
81123
81124                         tv_val = ref.value;
81125                         DUK_ASSERT(tv_val != NULL);
81126                         DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val);  /* side effects */
81127
81128                         /* ref.value invalidated here */
81129                 } else {
81130                         DUK_ASSERT(ref.holder != NULL);
81131
81132                         DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
81133                         DUK_TVAL_SET_STRING(&tv_tmp_key, name);
81134                         (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
81135
81136                         /* ref.value invalidated here */
81137                 }
81138
81139                 return;
81140         }
81141
81142         /*
81143          *  Not found: write to global object (non-strict) or ReferenceError
81144          *  (strict); see E5 Section 8.7.2, step 3.
81145          */
81146
81147         if (strict) {
81148                 DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
81149                 DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
81150                                "identifier '%s' undefined",
81151                                (const char *) DUK_HSTRING_GET_DATA(name));
81152                 DUK_WO_NORETURN(return;);
81153         }
81154
81155         DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
81156
81157         DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
81158         DUK_TVAL_SET_STRING(&tv_tmp_key, name);
81159         (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0);  /* 0 = no throw */
81160
81161         /* NB: 'val' may be invalidated here because put_value may realloc valstack,
81162          * caller beware.
81163          */
81164 }
81165
81166 DUK_INTERNAL
81167 void duk_js_putvar_envrec(duk_hthread *thr,
81168                           duk_hobject *env,
81169                           duk_hstring *name,
81170                           duk_tval *val,
81171                           duk_bool_t strict) {
81172         duk__putvar_helper(thr, env, NULL, name, val, strict);
81173 }
81174
81175 DUK_INTERNAL
81176 void duk_js_putvar_activation(duk_hthread *thr,
81177                               duk_activation *act,
81178                               duk_hstring *name,
81179                               duk_tval *val,
81180                               duk_bool_t strict) {
81181         DUK_ASSERT(act != NULL);
81182         duk__putvar_helper(thr, act->lex_env, act, name, val, strict);
81183 }
81184
81185 /*
81186  *  DELVAR
81187  *
81188  *  See E5 Sections:
81189  *    11.4.1 The delete operator
81190  *    10.2.1.1.5 DeleteBinding (N)  [declarative environment record]
81191  *    10.2.1.2.5 DeleteBinding (N)  [object environment record]
81192  *
81193  *  Variable bindings established inside eval() are deletable (configurable),
81194  *  other bindings are not, including variables declared in global level.
81195  *  Registers are always non-deletable, and the deletion of other bindings
81196  *  is controlled by the configurable flag.
81197  *
81198  *  For strict mode code, the 'delete' operator should fail with a compile
81199  *  time SyntaxError if applied to identifiers.  Hence, no strict mode
81200  *  run-time deletion of identifiers should ever happen.  This function
81201  *  should never be called from strict mode code!
81202  */
81203
81204 DUK_LOCAL
81205 duk_bool_t duk__delvar_helper(duk_hthread *thr,
81206                               duk_hobject *env,
81207                               duk_activation *act,
81208                               duk_hstring *name) {
81209         duk__id_lookup_result ref;
81210         duk_bool_t parents;
81211
81212         DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O "
81213                              "(env -> %!dO)",
81214                              (void *) thr, (void *) env, (void *) act,
81215                              (duk_heaphdr *) name, (duk_heaphdr *) env));
81216
81217         DUK_ASSERT(thr != NULL);
81218         DUK_ASSERT(name != NULL);
81219         /* env and act may be NULL */
81220
81221         DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
81222
81223         parents = 1;     /* follow parent chain */
81224
81225         if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
81226                 if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
81227                         /* Identifier found in registers (always non-deletable)
81228                          * or declarative environment record and non-configurable.
81229                          */
81230                         return 0;
81231                 }
81232                 DUK_ASSERT(ref.holder != NULL);
81233
81234                 return duk_hobject_delprop_raw(thr, ref.holder, name, 0);
81235         }
81236
81237         /*
81238          *  Not found (even in global object).
81239          *
81240          *  In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1,
81241          *  step 3.b.  In strict mode this case is a compile time SyntaxError so
81242          *  we should not come here.
81243          */
81244
81245         DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O "
81246                              "(treated as silent success)",
81247                              (duk_heaphdr *) name));
81248         return 1;
81249 }
81250
81251 #if 0  /*unused*/
81252 DUK_INTERNAL
81253 duk_bool_t duk_js_delvar_envrec(duk_hthread *thr,
81254                                 duk_hobject *env,
81255                                 duk_hstring *name) {
81256         return duk__delvar_helper(thr, env, NULL, name);
81257 }
81258 #endif
81259
81260 DUK_INTERNAL
81261 duk_bool_t duk_js_delvar_activation(duk_hthread *thr,
81262                                     duk_activation *act,
81263                                     duk_hstring *name) {
81264         DUK_ASSERT(act != NULL);
81265         return duk__delvar_helper(thr, act->lex_env, act, name);
81266 }
81267
81268 /*
81269  *  DECLVAR
81270  *
81271  *  See E5 Sections:
81272  *    10.4.3 Entering Function Code
81273  *    10.5 Declaration Binding Instantion
81274  *    12.2 Variable Statement
81275  *    11.1.2 Identifier Reference
81276  *    10.3.1 Identifier Resolution
81277  *
81278  *  Variable declaration behavior is mainly discussed in Section 10.5,
81279  *  and is not discussed in the execution semantics (Sections 11-13).
81280  *
81281  *  Conceptually declarations happen when code (global, eval, function)
81282  *  is entered, before any user code is executed.  In practice, register-
81283  *  bound identifiers are 'declared' automatically (by virtue of being
81284  *  allocated to registers with the initial value 'undefined').  Other
81285  *  identifiers are declared in the function prologue with this primitive.
81286  *
81287  *  Since non-register bindings eventually back to an internal object's
81288  *  properties, the 'prop_flags' argument is used to specify binding
81289  *  type:
81290  *
81291  *    - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false
81292  *    - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false
81293  *    - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it
81294  *      doesn't really matter for internal objects
81295  *
81296  *  All bindings are non-deletable mutable bindings except:
81297  *
81298  *    - Declarations in eval code (mutable, deletable)
81299  *    - 'arguments' binding in strict function code (immutable)
81300  *    - Function name binding of a function expression (immutable)
81301  *
81302  *  Declarations may go to declarative environment records (always
81303  *  so for functions), but may also go to object environment records
81304  *  (e.g. global code).  The global object environment has special
81305  *  behavior when re-declaring a function (but not a variable); see
81306  *  E5.1 specification, Section 10.5, step 5.e.
81307  *
81308  *  Declarations always go to the 'top-most' environment record, i.e.
81309  *  we never check the record chain.  It's not an error even if a
81310  *  property (even an immutable or non-deletable one) of the same name
81311  *  already exists.
81312  *
81313  *  If a declared variable already exists, its value needs to be updated
81314  *  (if possible).  Returns 1 if a PUTVAR needs to be done by the caller;
81315  *  otherwise returns 0.
81316  */
81317
81318 DUK_LOCAL
81319 duk_bool_t duk__declvar_helper(duk_hthread *thr,
81320                                duk_hobject *env,
81321                                duk_hstring *name,
81322                                duk_tval *val,
81323                                duk_small_uint_t prop_flags,
81324                                duk_bool_t is_func_decl) {
81325         duk_hobject *holder;
81326         duk_bool_t parents;
81327         duk__id_lookup_result ref;
81328         duk_tval *tv;
81329
81330         DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld "
81331                              "(env -> %!iO)",
81332                              (void *) thr, (void *) env, (duk_heaphdr *) name,
81333                              (duk_tval *) val, (unsigned long) prop_flags,
81334                              (unsigned int) is_func_decl, (duk_heaphdr *) env));
81335
81336         DUK_ASSERT(thr != NULL);
81337         DUK_ASSERT(env != NULL);
81338         DUK_ASSERT(name != NULL);
81339         DUK_ASSERT(val != NULL);
81340
81341         /* Note: in strict mode the compiler should reject explicit
81342          * declaration of 'eval' or 'arguments'.  However, internal
81343          * bytecode may declare 'arguments' in the function prologue.
81344          * We don't bother checking (or asserting) for these now.
81345          */
81346
81347         /* Note: val is a stable duk_tval pointer.  The caller makes
81348          * a value copy into its stack frame, so 'tv_val' is not subject
81349          * to side effects here.
81350          */
81351
81352         /*
81353          *  Check whether already declared.
81354          *
81355          *  We need to check whether the binding exists in the environment
81356          *  without walking its parents.  However, we still need to check
81357          *  register-bound identifiers and the prototype chain of an object
81358          *  environment target object.
81359          */
81360
81361         parents = 0;  /* just check 'env' */
81362         if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
81363                 duk_int_t e_idx;
81364                 duk_int_t h_idx;
81365                 duk_small_uint_t flags;
81366
81367                 /*
81368                  *  Variable already declared, ignore re-declaration.
81369                  *  The only exception is the updated behavior of E5.1 for
81370                  *  global function declarations, E5.1 Section 10.5, step 5.e.
81371                  *  This behavior does not apply to global variable declarations.
81372                  */
81373
81374                 if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) {
81375                         DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring"));
81376                         return 1;  /* 1 -> needs a PUTVAR */
81377                 }
81378
81379                 /*
81380                  *  Special behavior in E5.1.
81381                  *
81382                  *  Note that even though parents == 0, the conflicting property
81383                  *  may be an inherited property (currently our global object's
81384                  *  prototype is Object.prototype).  Step 5.e first operates on
81385                  *  the existing property (which is potentially in an ancestor)
81386                  *  and then defines a new property in the global object (and
81387                  *  never modifies the ancestor).
81388                  *
81389                  *  Also note that this logic would become even more complicated
81390                  *  if the conflicting property might be a virtual one.  Object
81391                  *  prototype has no virtual properties, though.
81392                  *
81393                  *  XXX: this is now very awkward, rework.
81394                  */
81395
81396                 DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, "
81397                                      "updated E5.1 processing"));
81398
81399                 DUK_ASSERT(ref.holder != NULL);
81400                 holder = ref.holder;
81401
81402                 /* holder will be set to the target object, not the actual object
81403                  * where the property was found (see duk__get_identifier_reference()).
81404                  */
81405                 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL);
81406                 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder));  /* global object doesn't have array part */
81407
81408                 /* XXX: use a helper for prototype traversal; no loop check here */
81409                 /* must be found: was found earlier, and cannot be inherited */
81410                 for (;;) {
81411                         DUK_ASSERT(holder != NULL);
81412                         if (duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx)) {
81413                                 DUK_ASSERT(e_idx >= 0);
81414                                 break;
81415                         }
81416                         /* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
81417                          * asserted above.
81418                          */
81419                         holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder);
81420                 }
81421                 DUK_ASSERT(holder != NULL);
81422                 DUK_ASSERT(e_idx >= 0);
81423                 /* SCANBUILD: scan-build produces a NULL pointer dereference warning
81424                  * below; it never actually triggers because holder is actually never
81425                  * NULL.
81426                  */
81427
81428                 /* ref.holder is global object, holder is the object with the
81429                  * conflicting property.
81430                  */
81431
81432                 flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx);
81433                 if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
81434                         if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
81435                                 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
81436                                                      "accessor -> reject"));
81437                                 goto fail_existing_attributes;
81438                         }
81439                         if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) &&
81440                               (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) {
81441                                 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
81442                                                      "plain property which is not writable and "
81443                                                      "enumerable -> reject"));
81444                                 goto fail_existing_attributes;
81445                         }
81446
81447                         DUK_DDD(DUK_DDDPRINT("existing property is not configurable but "
81448                                              "is plain, enumerable, and writable -> "
81449                                              "allow redeclaration"));
81450                 }
81451
81452                 if (holder == ref.holder) {
81453                         /* XXX: if duk_hobject_define_property_internal() was updated
81454                          * to handle a pre-existing accessor property, this would be
81455                          * a simple call (like for the ancestor case).
81456                          */
81457                         DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself"));
81458
81459                         if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
81460                                 duk_hobject *tmp;
81461
81462                                 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx);
81463                                 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL);
81464                                 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
81465                                 DUK_UNREF(tmp);
81466                                 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx);
81467                                 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL);
81468                                 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
81469                                 DUK_UNREF(tmp);
81470                         } else {
81471                                 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
81472                                 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);
81473                         }
81474
81475                         /* Here val would be potentially invalid if we didn't make
81476                          * a value copy at the caller.
81477                          */
81478
81479                         tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
81480                         DUK_TVAL_SET_TVAL(tv, val);
81481                         DUK_TVAL_INCREF(thr, tv);
81482                         DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags);
81483
81484                         DUK_DDD(DUK_DDDPRINT("updated global binding, final result: "
81485                                              "value -> %!T, prop_flags=0x%08lx",
81486                                              (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx),
81487                                              (unsigned long) prop_flags));
81488                 } else {
81489                         DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
81490
81491                         DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
81492                         duk_push_tval(thr, val);
81493                         duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
81494                 }
81495
81496                 return 0;
81497         }
81498
81499         /*
81500          *  Not found (in registers or record objects).  Declare
81501          *  to current variable environment.
81502          */
81503
81504         /*
81505          *  Get holder object
81506          */
81507
81508         if (DUK_HOBJECT_IS_DECENV(env)) {
81509                 DUK_ASSERT_HDECENV_VALID((duk_hdecenv *) env);
81510                 holder = env;
81511         } else {
81512                 DUK_ASSERT_HOBJENV_VALID((duk_hobjenv *) env);
81513                 holder = ((duk_hobjenv *) env)->target;
81514                 DUK_ASSERT(holder != NULL);
81515         }
81516
81517         /*
81518          *  Define new property
81519          *
81520          *  Note: this may fail if the holder is not extensible.
81521          */
81522
81523         /* XXX: this is awkward as we use an internal method which doesn't handle
81524          * extensibility etc correctly.  Basically we'd want to do a [[DefineOwnProperty]]
81525          * or Object.defineProperty() here.
81526          */
81527
81528         if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) {
81529                 goto fail_not_extensible;
81530         }
81531
81532         duk_push_hobject(thr, holder);
81533         duk_push_hstring(thr, name);
81534         duk_push_tval(thr, val);
81535         duk_xdef_prop(thr, -3, prop_flags);  /* [holder name val] -> [holder] */
81536         duk_pop_unsafe(thr);
81537
81538         return 0;
81539
81540  fail_existing_attributes:
81541  fail_not_extensible:
81542         DUK_ERROR_TYPE(thr, "declaration failed");
81543         DUK_WO_NORETURN(return 0;);
81544 }
81545
81546 DUK_INTERNAL
81547 duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
81548                                      duk_activation *act,
81549                                      duk_hstring *name,
81550                                      duk_tval *val,
81551                                      duk_small_uint_t prop_flags,
81552                                      duk_bool_t is_func_decl) {
81553         duk_hobject *env;
81554         duk_tval tv_val_copy;
81555
81556         DUK_ASSERT(act != NULL);
81557
81558         /*
81559          *  Make a value copy of the input val.  This ensures that
81560          *  side effects cannot invalidate the pointer.
81561          */
81562
81563         DUK_TVAL_SET_TVAL(&tv_val_copy, val);
81564         val = &tv_val_copy;
81565
81566         /*
81567          *  Delayed env creation check
81568          */
81569
81570         if (!act->var_env) {
81571                 DUK_ASSERT(act->lex_env == NULL);
81572                 duk_js_init_activation_environment_records_delayed(thr, act);
81573                 /* 'act' is a stable pointer, so still OK. */
81574         }
81575         DUK_ASSERT(act->lex_env != NULL);
81576         DUK_ASSERT(act->var_env != NULL);
81577
81578         env = act->var_env;
81579         DUK_ASSERT(env != NULL);
81580         DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
81581
81582         return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl);
81583 }
81584 #line 1 "duk_lexer.c"
81585 /*
81586  *  Lexer for source files, ToNumber() string conversions, RegExp expressions,
81587  *  and JSON.
81588  *
81589  *  Provides a stream of ECMAScript tokens from an UTF-8/CESU-8 buffer.  The
81590  *  caller can also rewind the token stream into a certain position which is
81591  *  needed by the compiler part for multi-pass scanning.  Tokens are
81592  *  represented as duk_token structures, and contain line number information.
81593  *  Token types are identified with DUK_TOK_* defines.
81594  *
81595  *  Characters are decoded into a fixed size lookup window consisting of
81596  *  decoded Unicode code points, with window positions past the end of the
81597  *  input filled with an invalid codepoint (-1).  The tokenizer can thus
81598  *  perform multiple character lookups efficiently and with few sanity
81599  *  checks (such as access outside the end of the input), which keeps the
81600  *  tokenization code small at the cost of performance.
81601  *
81602  *  Character data in tokens, such as identifier names and string literals,
81603  *  is encoded into CESU-8 format on-the-fly while parsing the token in
81604  *  question.  The string data is made reachable to garbage collection by
81605  *  placing the token-related values in value stack entries allocated for
81606  *  this purpose by the caller.  The characters exist in Unicode code point
81607  *  form only in the fixed size lookup window, which keeps character data
81608  *  expansion (of especially ASCII data) low.
81609  *
81610  *  Token parsing supports the full range of Unicode characters as described
81611  *  in the E5 specification.  Parsing has been optimized for ASCII characters
81612  *  because ordinary ECMAScript code consists almost entirely of ASCII
81613  *  characters.  Matching of complex Unicode codepoint sets (such as in the
81614  *  IdentifierStart and IdentifierPart productions) is optimized for size,
81615  *  and is done using a linear scan of a bit-packed list of ranges.  This is
81616  *  very slow, but should never be entered unless the source code actually
81617  *  contains Unicode characters.
81618  *
81619  *  ECMAScript tokenization is partially context sensitive.  First,
81620  *  additional future reserved words are recognized in strict mode (see E5
81621  *  Section 7.6.1.2).  Second, a forward slash character ('/') can be
81622  *  recognized either as starting a RegExp literal or as a division operator,
81623  *  depending on context.  The caller must provide necessary context flags
81624  *  when requesting a new token.
81625  *
81626  *  Future work:
81627  *
81628  *    * Make line number tracking optional, as it consumes space.
81629  *
81630  *    * Add a feature flag for disabling UTF-8 decoding of input, as most
81631  *      source code is ASCII.  Because of Unicode escapes written in ASCII,
81632  *      this does not allow Unicode support to be removed from e.g.
81633  *      duk_unicode_is_identifier_start() nor does it allow removal of CESU-8
81634  *      encoding of e.g. string literals.
81635  *
81636  *    * Add a feature flag for disabling Unicode compliance of e.g. identifier
81637  *      names.  This allows for a build more than a kilobyte smaller, because
81638  *      Unicode ranges needed by duk_unicode_is_identifier_start() and
81639  *      duk_unicode_is_identifier_part() can be dropped.  String literals
81640  *      should still be allowed to contain escaped Unicode, so this still does
81641  *      not allow removal of CESU-8 encoding of e.g. string literals.
81642  *
81643  *    * Character lookup tables for codepoints above BMP could be stripped.
81644  *
81645  *    * Strictly speaking, E5 specification requires that source code consists
81646  *      of 16-bit code units, and if not, must be conceptually converted to
81647  *      that format first.  The current lexer processes Unicode code points
81648  *      and allows characters outside the BMP.  These should be converted to
81649  *      surrogate pairs while reading the source characters into the window,
81650  *      not after tokens have been formed (as is done now).  However, the fix
81651  *      is not trivial because two characters are decoded from one codepoint.
81652  *
81653  *    * Optimize for speed as well as size.  Large if-else ladders are (at
81654  *      least potentially) slow.
81655  */
81656
81657 /* #include duk_internal.h -> already included */
81658
81659 /*
81660  *  Various defines and file specific helper macros
81661  */
81662
81663 #define DUK__MAX_RE_DECESC_DIGITS     9
81664 #define DUK__MAX_RE_QUANT_DIGITS      9   /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */
81665
81666 /* whether to use macros or helper function depends on call count */
81667 #define DUK__ISDIGIT(x)          ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_9)
81668 #define DUK__ISHEXDIGIT(x)       duk__is_hex_digit((x))
81669 #define DUK__ISOCTDIGIT(x)       ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_7)
81670 #define DUK__ISDIGIT03(x)        ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_3)
81671 #define DUK__ISDIGIT47(x)        ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7)
81672
81673 /* lexer character window helpers */
81674 #define DUK__LOOKUP(lex_ctx,idx)            ((lex_ctx)->window[(idx)].codepoint)
81675 #define DUK__ADVANCECHARS(lex_ctx,count)    duk__advance_chars((lex_ctx), (count))
81676 #define DUK__ADVANCEBYTES(lex_ctx,count)    duk__advance_bytes((lex_ctx), (count))
81677 #define DUK__INITBUFFER(lex_ctx)            duk__initbuffer((lex_ctx))
81678 #define DUK__APPENDBUFFER(lex_ctx,x)        duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x))
81679 #define DUK__APPENDBUFFER_ASCII(lex_ctx,x)  duk__appendbuffer_ascii((lex_ctx), (duk_codepoint_t) (x))
81680
81681 /* lookup shorthands (note: assume context variable is named 'lex_ctx') */
81682 #define DUK__L0()  DUK__LOOKUP(lex_ctx, 0)
81683 #define DUK__L1()  DUK__LOOKUP(lex_ctx, 1)
81684 #define DUK__L2()  DUK__LOOKUP(lex_ctx, 2)
81685 #define DUK__L3()  DUK__LOOKUP(lex_ctx, 3)
81686 #define DUK__L4()  DUK__LOOKUP(lex_ctx, 4)
81687 #define DUK__L5()  DUK__LOOKUP(lex_ctx, 5)
81688
81689 /* packed advance/token number macro used by multiple functions */
81690 #define DUK__ADVTOK(advbytes,tok)  ((((advbytes) * sizeof(duk_lexer_codepoint)) << 8) + (tok))
81691
81692 /*
81693  *  Advance lookup window by N characters, filling in new characters as
81694  *  necessary.  After returning caller is guaranteed a character window of
81695  *  at least DUK_LEXER_WINDOW_SIZE characters.
81696  *
81697  *  The main function duk__advance_bytes() is called at least once per every
81698  *  token so it has a major lexer/compiler performance impact.  There are two
81699  *  variants for the main duk__advance_bytes() algorithm: a sliding window
81700  *  approach which is slightly faster at the cost of larger code footprint,
81701  *  and a simple copying one.
81702  *
81703  *  Decoding directly from the source string would be another lexing option.
81704  *  But the lookup window based approach has the advantage of hiding the
81705  *  source string and its encoding effectively which gives more flexibility
81706  *  going forward to e.g. support chunked streaming of source from flash.
81707  *
81708  *  Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to
81709  *  U+10FFFF, causing an error if the input is unparseable.  Leniency means:
81710  *
81711  *    * Unicode code point validation is intentionally not performed,
81712  *      except to check that the codepoint does not exceed 0x10ffff.
81713  *
81714  *    * In particular, surrogate pairs are allowed and not combined, which
81715  *      allows source files to represent all SourceCharacters with CESU-8.
81716  *      Broken surrogate pairs are allowed, as ECMAScript does not mandate
81717  *      their validation.
81718  *
81719  *    * Allow non-shortest UTF-8 encodings.
81720  *
81721  *  Leniency here causes few security concerns because all character data is
81722  *  decoded into Unicode codepoints before lexer processing, and is then
81723  *  re-encoded into CESU-8.  The source can be parsed as strict UTF-8 with
81724  *  a compiler option.  However, ECMAScript source characters include -all-
81725  *  16-bit unsigned integer codepoints, so leniency seems to be appropriate.
81726  *
81727  *  Note that codepoints above the BMP are not strictly SourceCharacters,
81728  *  but the lexer still accepts them as such.  Before ending up in a string
81729  *  or an identifier name, codepoints above BMP are converted into surrogate
81730  *  pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as
81731  *  expected by ECMAScript.
81732  *
81733  *  An alternative approach to dealing with invalid or partial sequences
81734  *  would be to skip them and replace them with e.g. the Unicode replacement
81735  *  character U+FFFD.  This has limited utility because a replacement character
81736  *  will most likely cause a parse error, unless it occurs inside a string.
81737  *  Further, ECMAScript source is typically pure ASCII.
81738  *
81739  *  See:
81740  *
81741  *     http://en.wikipedia.org/wiki/UTF-8
81742  *     http://en.wikipedia.org/wiki/CESU-8
81743  *     http://tools.ietf.org/html/rfc3629
81744  *     http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
81745  *
81746  *  Future work:
81747  *
81748  *    * Reject other invalid Unicode sequences (see Wikipedia entry for examples)
81749  *      in strict UTF-8 mode.
81750  *
81751  *    * Size optimize.  An attempt to use a 16-byte lookup table for the first
81752  *      byte resulted in a code increase though.
81753  *
81754  *    * Is checking against maximum 0x10ffff really useful?  4-byte encoding
81755  *      imposes a certain limit anyway.
81756  *
81757  *    * Support chunked streaming of source code.  Can be implemented either
81758  *      by streaming chunks of bytes or chunks of codepoints.
81759  */
81760
81761 #if defined(DUK_USE_LEXER_SLIDING_WINDOW)
81762 DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t start_offset_bytes) {
81763         duk_lexer_codepoint *cp, *cp_end;
81764         duk_ucodepoint_t x;
81765         duk_small_uint_t contlen;
81766         const duk_uint8_t *p, *p_end;
81767 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
81768         duk_ucodepoint_t mincp;
81769 #endif
81770         duk_int_t input_line;
81771
81772         /* Use temporaries and update lex_ctx only when finished. */
81773         input_line = lex_ctx->input_line;
81774         p = lex_ctx->input + lex_ctx->input_offset;
81775         p_end = lex_ctx->input + lex_ctx->input_length;
81776
81777         cp = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->buffer + start_offset_bytes);
81778         cp_end = lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE;
81779
81780         for (; cp != cp_end; cp++) {
81781                 cp->offset = (duk_size_t) (p - lex_ctx->input);
81782                 cp->line = input_line;
81783
81784                 /* XXX: potential issue with signed pointers, p_end < p. */
81785                 if (DUK_UNLIKELY(p >= p_end)) {
81786                         /* If input_offset were assigned a negative value, it would
81787                          * result in a large positive value.  Most likely it would be
81788                          * larger than input_length and be caught here.  In any case
81789                          * no memory unsafe behavior would happen.
81790                          */
81791                         cp->codepoint = -1;
81792                         continue;
81793                 }
81794
81795                 x = (duk_ucodepoint_t) (*p++);
81796
81797                 /* Fast path. */
81798
81799                 if (DUK_LIKELY(x < 0x80UL)) {
81800                         DUK_ASSERT(x != 0x2028UL && x != 0x2029UL);  /* not LS/PS */
81801                         if (DUK_UNLIKELY(x <= 0x000dUL)) {
81802                                 if ((x == 0x000aUL) ||
81803                                     ((x == 0x000dUL) && (p >= p_end || *p != 0x000aUL))) {
81804                                         /* lookup for 0x000a above assumes shortest encoding now */
81805
81806                                         /* E5 Section 7.3, treat the following as newlines:
81807                                          *   LF
81808                                          *   CR [not followed by LF]
81809                                          *   LS
81810                                          *   PS
81811                                          *
81812                                          * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
81813                                          * the line number.
81814                                          */
81815                                         input_line++;
81816                                 }
81817                         }
81818
81819                         cp->codepoint = (duk_codepoint_t) x;
81820                         continue;
81821                 }
81822
81823                 /* Slow path. */
81824
81825                 if (x < 0xc0UL) {
81826                         /* 10xx xxxx -> invalid */
81827                         goto error_encoding;
81828                 } else if (x < 0xe0UL) {
81829                         /* 110x xxxx   10xx xxxx  */
81830                         contlen = 1;
81831 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
81832                         mincp = 0x80UL;
81833 #endif
81834                         x = x & 0x1fUL;
81835                 } else if (x < 0xf0UL) {
81836                         /* 1110 xxxx   10xx xxxx   10xx xxxx */
81837                         contlen = 2;
81838 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
81839                         mincp = 0x800UL;
81840 #endif
81841                         x = x & 0x0fUL;
81842                 } else if (x < 0xf8UL) {
81843                         /* 1111 0xxx   10xx xxxx   10xx xxxx   10xx xxxx */
81844                         contlen = 3;
81845 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
81846                         mincp = 0x10000UL;
81847 #endif
81848                         x = x & 0x07UL;
81849                 } else {
81850                         /* no point in supporting encodings of 5 or more bytes */
81851                         goto error_encoding;
81852                 }
81853
81854                 DUK_ASSERT(p_end >= p);
81855                 if ((duk_size_t) contlen > (duk_size_t) (p_end - p)) {
81856                         goto error_clipped;
81857                 }
81858
81859                 while (contlen > 0) {
81860                         duk_small_uint_t y;
81861                         y = *p++;
81862                         if ((y & 0xc0U) != 0x80U) {
81863                                 /* check that byte has the form 10xx xxxx */
81864                                 goto error_encoding;
81865                         }
81866                         x = x << 6;
81867                         x += y & 0x3fUL;
81868                         contlen--;
81869                 }
81870
81871                 /* check final character validity */
81872
81873                 if (x > 0x10ffffUL) {
81874                         goto error_encoding;
81875                 }
81876 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
81877                 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
81878                         goto error_encoding;
81879                 }
81880 #endif
81881
81882                 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
81883                 if ((x == 0x2028UL) || (x == 0x2029UL)) {
81884                         input_line++;
81885                 }
81886
81887                 cp->codepoint = (duk_codepoint_t) x;
81888         }
81889
81890         lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
81891         lex_ctx->input_line = input_line;
81892         return;
81893
81894  error_clipped:   /* clipped codepoint */
81895  error_encoding:  /* invalid codepoint encoding or codepoint */
81896         lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
81897         lex_ctx->input_line = input_line;
81898
81899         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED);
81900         DUK_WO_NORETURN(return;);
81901 }
81902
81903 DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
81904         duk_small_uint_t used_bytes, avail_bytes;
81905
81906         DUK_ASSERT_DISABLE(count_bytes >= 0);  /* unsigned */
81907         DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
81908         DUK_ASSERT(lex_ctx->window >= lex_ctx->buffer);
81909         DUK_ASSERT(lex_ctx->window < lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE);
81910         DUK_ASSERT((duk_uint8_t *) lex_ctx->window + count_bytes <= (duk_uint8_t *) lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint));
81911
81912         /* Zero 'count' is also allowed to make call sites easier.
81913          * Arithmetic in bytes generates better code in GCC.
81914          */
81915
81916         lex_ctx->window = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->window + count_bytes);  /* avoid multiply */
81917         used_bytes = (duk_small_uint_t) ((duk_uint8_t *) lex_ctx->window - (duk_uint8_t *) lex_ctx->buffer);
81918         avail_bytes = DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint) - used_bytes;
81919         if (avail_bytes < (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))) {
81920                 /* Not enough data to provide a full window, so "scroll" window to
81921                  * start of buffer and fill up the rest.
81922                  */
81923                 duk_memmove((void *) lex_ctx->buffer,
81924                             (const void *) lex_ctx->window,
81925                             (size_t) avail_bytes);
81926                 lex_ctx->window = lex_ctx->buffer;
81927                 duk__fill_lexer_buffer(lex_ctx, avail_bytes);
81928         }
81929 }
81930
81931 DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
81932         lex_ctx->window = lex_ctx->buffer;
81933         duk__fill_lexer_buffer(lex_ctx, 0);
81934 }
81935 #else  /* DUK_USE_LEXER_SLIDING_WINDOW */
81936 DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
81937         duk_ucodepoint_t x;
81938         duk_small_uint_t len;
81939         duk_small_uint_t i;
81940         const duk_uint8_t *p;
81941 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
81942         duk_ucodepoint_t mincp;
81943 #endif
81944         duk_size_t input_offset;
81945
81946         input_offset = lex_ctx->input_offset;
81947         if (DUK_UNLIKELY(input_offset >= lex_ctx->input_length)) {
81948                 /* If input_offset were assigned a negative value, it would
81949                  * result in a large positive value.  Most likely it would be
81950                  * larger than input_length and be caught here.  In any case
81951                  * no memory unsafe behavior would happen.
81952                  */
81953                 return -1;
81954         }
81955
81956         p = lex_ctx->input + input_offset;
81957         x = (duk_ucodepoint_t) (*p);
81958
81959         if (DUK_LIKELY(x < 0x80UL)) {
81960                 /* 0xxx xxxx -> fast path */
81961
81962                 /* input offset tracking */
81963                 lex_ctx->input_offset++;
81964
81965                 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL);  /* not LS/PS */
81966                 if (DUK_UNLIKELY(x <= 0x000dUL)) {
81967                         if ((x == 0x000aUL) ||
81968                             ((x == 0x000dUL) && (lex_ctx->input_offset >= lex_ctx->input_length ||
81969                                                  lex_ctx->input[lex_ctx->input_offset] != 0x000aUL))) {
81970                                 /* lookup for 0x000a above assumes shortest encoding now */
81971
81972                                 /* E5 Section 7.3, treat the following as newlines:
81973                                  *   LF
81974                                  *   CR [not followed by LF]
81975                                  *   LS
81976                                  *   PS
81977                                  *
81978                                  * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
81979                                  * the line number.
81980                                  */
81981                                 lex_ctx->input_line++;
81982                         }
81983                 }
81984
81985                 return (duk_codepoint_t) x;
81986         }
81987
81988         /* Slow path. */
81989
81990         if (x < 0xc0UL) {
81991                 /* 10xx xxxx -> invalid */
81992                 goto error_encoding;
81993         } else if (x < 0xe0UL) {
81994                 /* 110x xxxx   10xx xxxx  */
81995                 len = 2;
81996 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
81997                 mincp = 0x80UL;
81998 #endif
81999                 x = x & 0x1fUL;
82000         } else if (x < 0xf0UL) {
82001                 /* 1110 xxxx   10xx xxxx   10xx xxxx */
82002                 len = 3;
82003 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
82004                 mincp = 0x800UL;
82005 #endif
82006                 x = x & 0x0fUL;
82007         } else if (x < 0xf8UL) {
82008                 /* 1111 0xxx   10xx xxxx   10xx xxxx   10xx xxxx */
82009                 len = 4;
82010 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
82011                 mincp = 0x10000UL;
82012 #endif
82013                 x = x & 0x07UL;
82014         } else {
82015                 /* no point in supporting encodings of 5 or more bytes */
82016                 goto error_encoding;
82017         }
82018
82019         DUK_ASSERT(lex_ctx->input_length >= lex_ctx->input_offset);
82020         if ((duk_size_t) len > (duk_size_t) (lex_ctx->input_length - lex_ctx->input_offset)) {
82021                 goto error_clipped;
82022         }
82023
82024         p++;
82025         for (i = 1; i < len; i++) {
82026                 duk_small_uint_t y;
82027                 y = *p++;
82028                 if ((y & 0xc0U) != 0x80U) {
82029                         /* check that byte has the form 10xx xxxx */
82030                         goto error_encoding;
82031                 }
82032                 x = x << 6;
82033                 x += y & 0x3fUL;
82034         }
82035
82036         /* check final character validity */
82037
82038         if (x > 0x10ffffUL) {
82039                 goto error_encoding;
82040         }
82041 #if defined(DUK_USE_STRICT_UTF8_SOURCE)
82042         if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
82043                 goto error_encoding;
82044         }
82045 #endif
82046
82047         /* input offset tracking */
82048         lex_ctx->input_offset += len;
82049
82050         /* line tracking */
82051         DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
82052         if ((x == 0x2028UL) || (x == 0x2029UL)) {
82053                 lex_ctx->input_line++;
82054         }
82055
82056         return (duk_codepoint_t) x;
82057
82058  error_clipped:   /* clipped codepoint */
82059  error_encoding:  /* invalid codepoint encoding or codepoint */
82060         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_SOURCE_DECODE_FAILED);
82061         DUK_WO_NORETURN(return 0;);
82062 }
82063
82064 DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
82065         duk_small_uint_t keep_bytes;
82066         duk_lexer_codepoint *cp, *cp_end;
82067
82068         DUK_ASSERT_DISABLE(count_bytes >= 0);  /* unsigned */
82069         DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
82070
82071         /* Zero 'count' is also allowed to make call sites easier. */
82072
82073         keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes;
82074         duk_memmove((void *) lex_ctx->window,
82075                     (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes),
82076                     (size_t) keep_bytes);
82077
82078         cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes);
82079         cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE;
82080         for (; cp != cp_end; cp++) {
82081                 cp->offset = lex_ctx->input_offset;
82082                 cp->line = lex_ctx->input_line;
82083                 cp->codepoint = duk__read_char(lex_ctx);
82084         }
82085 }
82086
82087 DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
82088         /* Call with count == DUK_LEXER_WINDOW_SIZE to fill buffer initially. */
82089         duk__advance_bytes(lex_ctx, DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint));  /* fill window */
82090 }
82091 #endif  /* DUK_USE_LEXER_SLIDING_WINDOW */
82092
82093 DUK_LOCAL void duk__advance_chars(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_chars) {
82094         duk__advance_bytes(lex_ctx, count_chars * sizeof(duk_lexer_codepoint));
82095 }
82096
82097 /*
82098  *  (Re)initialize the temporary byte buffer.  May be called extra times
82099  *  with little impact.
82100  */
82101
82102 DUK_LOCAL void duk__initbuffer(duk_lexer_ctx *lex_ctx) {
82103         /* Reuse buffer as is unless buffer has grown large. */
82104         if (DUK_HBUFFER_DYNAMIC_GET_SIZE(lex_ctx->buf) < DUK_LEXER_TEMP_BUF_LIMIT) {
82105                 /* Keep current size */
82106         } else {
82107                 duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, DUK_LEXER_TEMP_BUF_LIMIT);
82108         }
82109
82110         DUK_BW_INIT_WITHBUF(lex_ctx->thr, &lex_ctx->bw, lex_ctx->buf);
82111 }
82112
82113 /*
82114  *  Append a Unicode codepoint to the temporary byte buffer.  Performs
82115  *  CESU-8 surrogate pair encoding for codepoints above the BMP.
82116  *  Existing surrogate pairs are allowed and also encoded into CESU-8.
82117  */
82118
82119 DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
82120         /*
82121          *  Since character data is only generated by decoding the source or by
82122          *  the compiler itself, we rely on the input codepoints being correct
82123          *  and avoid a check here.
82124          *
82125          *  Character data can also come here through decoding of Unicode
82126          *  escapes ("\udead\ubeef") so all 16-but unsigned values can be
82127          *  present, even when the source file itself is strict UTF-8.
82128          */
82129         DUK_ASSERT(x >= 0 && x <= 0x10ffffL);
82130
82131         DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x);
82132 }
82133
82134 DUK_LOCAL void duk__appendbuffer_ascii(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
82135         /* ASCII characters can be emitted as a single byte without encoding
82136          * which matters for some fast paths.
82137          */
82138         DUK_ASSERT(x >= 0 && x <= 0x7f);
82139
82140         DUK_BW_WRITE_ENSURE_U8(lex_ctx->thr, &lex_ctx->bw, (duk_uint8_t) x);
82141 }
82142
82143 /*
82144  *  Intern the temporary byte buffer into a valstack slot
82145  *  (in practice, slot1 or slot2).
82146  */
82147
82148 DUK_LOCAL duk_hstring *duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
82149         DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
82150
82151         DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw);
82152         duk_replace(lex_ctx->thr, valstack_idx);
82153         return duk_known_hstring(lex_ctx->thr, valstack_idx);
82154 }
82155
82156 /*
82157  *  Init lexer context
82158  */
82159
82160 DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) {
82161         DUK_ASSERT(lex_ctx != NULL);
82162
82163         duk_memzero(lex_ctx, sizeof(*lex_ctx));
82164 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
82165 #if defined(DUK_USE_LEXER_SLIDING_WINDOW)
82166         lex_ctx->window = NULL;
82167 #endif
82168         lex_ctx->thr = NULL;
82169         lex_ctx->input = NULL;
82170         lex_ctx->buf = NULL;
82171 #endif
82172 }
82173
82174 /*
82175  *  Set lexer input position and reinitialize lookup window.
82176  */
82177
82178 DUK_INTERNAL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
82179         pt->offset = lex_ctx->window[0].offset;
82180         pt->line = lex_ctx->window[0].line;
82181 }
82182
82183 DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
82184         DUK_ASSERT_DISABLE(pt->offset >= 0);  /* unsigned */
82185         DUK_ASSERT(pt->line >= 1);
82186         lex_ctx->input_offset = pt->offset;
82187         lex_ctx->input_line = pt->line;
82188         duk__init_lexer_window(lex_ctx);
82189 }
82190
82191 /*
82192  *  Lexing helpers
82193  */
82194
82195 /* Numeric value of a hex digit (also covers octal and decimal digits) or
82196  * -1 if not a valid hex digit.
82197  */
82198 DUK_LOCAL duk_codepoint_t duk__hexval_validate(duk_codepoint_t x) {
82199         duk_small_int_t t;
82200
82201         /* Here 'x' is a Unicode codepoint */
82202         if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
82203                 t = duk_hex_dectab[x];
82204                 if (DUK_LIKELY(t >= 0)) {
82205                         return t;
82206                 }
82207         }
82208
82209         return -1;
82210 }
82211
82212 /* Just a wrapper for call sites where 'x' is known to be valid so
82213  * we assert for it before decoding.
82214  */
82215 DUK_LOCAL duk_codepoint_t duk__hexval(duk_codepoint_t x) {
82216         duk_codepoint_t ret;
82217
82218         DUK_ASSERT((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
82219                    (x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_F) ||
82220                    (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_F));
82221         ret = duk__hexval_validate(x);
82222         DUK_ASSERT(ret >= 0 && ret <= 15);
82223         return ret;
82224 }
82225
82226 /* having this as a separate function provided a size benefit */
82227 DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) {
82228         if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
82229                 return (duk_hex_dectab[x] >= 0);
82230         }
82231         return 0;
82232 }
82233
82234 /* Parse a Unicode escape of the form \xHH, \uHHHH, or \u{H+}.  Shared by
82235  * source and RegExp parsing.
82236  */
82237 DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bool_t allow_es6) {
82238         duk_small_int_t digits;  /* Initial value 2 or 4 for fixed length escapes, 0 for ES2015 \u{H+}. */
82239         duk_codepoint_t escval;
82240         duk_codepoint_t x;
82241         duk_small_uint_t adv;
82242
82243         DUK_ASSERT(DUK__L0() == DUK_ASC_BACKSLASH);  /* caller responsibilities */
82244         DUK_ASSERT(DUK__L1() == DUK_ASC_LC_X || DUK__L1() == DUK_ASC_LC_U);
82245         DUK_UNREF(allow_es6);
82246
82247         adv = 2;
82248         digits = 2;
82249         if (DUK__L1() == DUK_ASC_LC_U) {
82250                 digits = 4;
82251 #if defined(DUK_USE_ES6_UNICODE_ESCAPE)
82252                 if (DUK__L2() == DUK_ASC_LCURLY && allow_es6) {
82253                         digits = 0;
82254                         adv = 3;
82255                 }
82256 #endif
82257         }
82258         DUK__ADVANCECHARS(lex_ctx, adv);
82259
82260         escval = 0;
82261         for (;;) {
82262                 /* One of the escape forms: \xHH, \uHHHH, \u{H+}.
82263                  * The 'digits' variable tracks parsing state and is
82264                  * initialized to:
82265                  *
82266                  *   \xHH     2
82267                  *   \uHH     4
82268                  *   \u{H+}   0 first time, updated to -1 to indicate
82269                  *            at least one digit has been parsed
82270                  *
82271                  * Octal parsing is handled separately because it can be
82272                  * done with fixed lookahead and also has validation
82273                  * rules which depend on the escape length (which is
82274                  * variable).
82275                  *
82276                  * We don't need a specific check for x < 0 (end of
82277                  * input) or duk_unicode_is_line_terminator(x)
82278                  * because the 'dig' decode will fail and lead to a
82279                  * SyntaxError.
82280                  */
82281                 duk_codepoint_t dig;
82282
82283                 x = DUK__L0();
82284                 DUK__ADVANCECHARS(lex_ctx, 1);
82285
82286                 dig = duk__hexval_validate(x);
82287                 if (digits > 0) {
82288                         digits--;
82289                         if (dig < 0) {
82290                                 goto fail_escape;
82291                         }
82292                         DUK_ASSERT(dig >= 0x00 && dig <= 0x0f);
82293                         escval = (escval << 4) + dig;
82294                         if (digits == 0) {
82295                                 DUK_ASSERT(escval >= 0 && escval <= 0xffffL);
82296                                 break;
82297                         }
82298                 } else {
82299 #if defined(DUK_USE_ES6_UNICODE_ESCAPE)
82300                         DUK_ASSERT(digits == 0 /* first time */ || digits == -1 /* others */);
82301                         if (dig >= 0) {
82302                                 DUK_ASSERT(dig >= 0x00 && dig <= 0x0f);
82303                                 escval = (escval << 4) + dig;
82304                                 if (escval > 0x10ffffL) {
82305                                         goto fail_escape;
82306                                 }
82307                         } else if (x == DUK_ASC_RCURLY) {
82308                                 if (digits == 0) {
82309                                         /* Empty escape, \u{}. */
82310                                         goto fail_escape;
82311                                 }
82312                                 DUK_ASSERT(escval >= 0 && escval <= 0x10ffffL);
82313                                 break;
82314                         } else {
82315                                 goto fail_escape;
82316                         }
82317                         digits = -1;  /* Indicate we have at least one digit. */
82318 #else  /* DUK_USE_ES6_UNICODE_ESCAPE */
82319                         DUK_ASSERT(0);  /* Never happens if \u{H+} support disabled. */
82320 #endif  /* DUK_USE_ES6_UNICODE_ESCAPE */
82321                 }
82322         }
82323
82324         return escval;
82325
82326  fail_escape:
82327         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
82328         DUK_WO_NORETURN(return 0;);
82329 }
82330
82331 /* Parse legacy octal escape of the form \N{1,3}, e.g. \0, \5, \0377.  Maximum
82332  * allowed value is \0377 (U+00FF), longest match is used.  Used for both string
82333  * RegExp octal escape parsing.  Window[0] must be the slash '\' and the first
82334  * digit must already be validated to be in [0-9] by the caller.
82335  */
82336 DUK_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) {
82337         duk_codepoint_t cp;
82338         duk_small_uint_t lookup_idx;
82339         duk_small_uint_t adv;
82340         duk_codepoint_t tmp;
82341
82342         DUK_ASSERT(out_adv != NULL);
82343         DUK_ASSERT(DUK__LOOKUP(lex_ctx, 0) == DUK_ASC_BACKSLASH);
82344         DUK_ASSERT(DUK__LOOKUP(lex_ctx, 1) >= DUK_ASC_0 && DUK__LOOKUP(lex_ctx, 1) <= DUK_ASC_9);
82345
82346         cp = 0;
82347         tmp = 0;
82348         for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) {
82349                 DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp));
82350                 tmp = DUK__LOOKUP(lex_ctx, lookup_idx);
82351                 if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) {
82352                         /* No more valid digits. */
82353                         break;
82354                 }
82355                 tmp = (cp << 3) + (tmp - DUK_ASC_0);
82356                 if (tmp > 0xff) {
82357                         /* Three digit octal escapes above \377 (= 0xff)
82358                          * are not allowed.
82359                          */
82360                         break;
82361                 }
82362                 cp = tmp;
82363         }
82364         DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, cp=%ld", (long) lookup_idx, (long) cp));
82365
82366         adv = lookup_idx;
82367         if (lookup_idx == 1) {
82368                 DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too"));
82369                 DUK_ASSERT(tmp == DUK_ASC_8 || tmp == DUK_ASC_9);
82370                 cp = tmp;
82371                 adv++;  /* correction to above, eat offending character */
82372         } else if (lookup_idx == 2 && cp == 0) {
82373                 /* Note: 'foo\0bar' is OK in strict mode, but 'foo\00bar' is not.
82374                  * It won't be interpreted as 'foo\u{0}0bar' but as a SyntaxError.
82375                  */
82376                 DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too"));
82377         } else {
82378                 /* This clause also handles non-shortest zero, e.g. \00. */
82379                 if (reject_annex_b) {
82380                         DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> reject in strict-mode", (long) cp));
82381                         cp = -1;
82382                 } else {
82383                         DUK_DDD(DUK_DDDPRINT("non-zero octal literal %ld -> accepted", (long) cp));
82384                         DUK_ASSERT(cp >= 0 && cp <= 0xff);
82385                 }
82386         }
82387
82388         *out_adv = adv;
82389
82390         DUK_ASSERT((cp >= 0 && cp <= 0xff) || (cp == -1 && reject_annex_b));
82391         return cp;
82392 }
82393
82394 /* XXX: move strict mode to lex_ctx? */
82395 DUK_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) {
82396         duk_small_uint_t adv;
82397
82398         for (adv = 1 /* initial quote */ ;;) {
82399                 duk_codepoint_t x;
82400
82401                 DUK__ADVANCECHARS(lex_ctx, adv);  /* eat opening quote on first loop */
82402                 x = DUK__L0();
82403
82404                 adv = 1;
82405                 if (x == quote) {
82406                         DUK__ADVANCECHARS(lex_ctx, 1);  /* eat closing quote */
82407                         break;
82408                 } else if (x == '\\') {
82409                         /* DUK__L0        -> '\' char
82410                          * DUK__L1 ... DUK__L5 -> more lookup
82411                          */
82412                         duk_small_int_t emitcp = -1;
82413
82414                         x = DUK__L1();
82415
82416                         /* How much to advance before next loop. */
82417                         adv = 2;  /* note: long live range */
82418
82419                         switch (x) {
82420                         case '\'':
82421                                 emitcp = 0x0027;
82422                                 break;
82423                         case '"':
82424                                 emitcp = 0x0022;
82425                                 break;
82426                         case '\\':
82427                                 emitcp = 0x005c;
82428                                 break;
82429                         case 'b':
82430                                 emitcp = 0x0008;
82431                                 break;
82432                         case 'f':
82433                                 emitcp = 0x000c;
82434                                 break;
82435                         case 'n':
82436                                 emitcp = 0x000a;
82437                                 break;
82438                         case 'r':
82439                                 emitcp = 0x000d;
82440                                 break;
82441                         case 't':
82442                                 emitcp = 0x0009;
82443                                 break;
82444                         case 'v':
82445                                 emitcp = 0x000b;
82446                                 break;
82447                         case 'x':
82448                         case 'u': {
82449                                 duk_codepoint_t esc_cp;
82450                                 esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/);
82451                                 DUK__APPENDBUFFER(lex_ctx, esc_cp);
82452                                 adv = 0;
82453                                 break;
82454                         }
82455                         default: {
82456                                 if (duk_unicode_is_line_terminator(x)) {
82457                                         /* line continuation */
82458                                         if (x == 0x000d && DUK__L2() == 0x000a) {
82459                                                 /* CR LF again a special case */
82460                                                 adv = 3;  /* line terminator, CR, LF */
82461                                         }
82462                                 } else if (DUK__ISDIGIT(x)) {
82463                                         /*
82464                                          *  Octal escape or zero escape:
82465                                          *    \0                                     (lookahead not OctalDigit)
82466                                          *    \1 ... \7                              (lookahead not OctalDigit)
82467                                          *    \ZeroToThree OctalDigit                (lookahead not OctalDigit)
82468                                          *    \FourToSeven OctalDigit                (no lookahead restrictions)
82469                                          *    \ZeroToThree OctalDigit OctalDigit     (no lookahead restrictions)
82470                                          *
82471                                          *  Zero escape is part of the standard syntax.  Octal escapes are
82472                                          *  defined in E5 Section B.1.2, and are only allowed in non-strict mode.
82473                                          *  Any other productions starting with a decimal digit are invalid
82474                                          *  but are in practice treated like identity escapes.
82475                                          *
82476                                          *  Parse octal (up to 3 digits) from the lookup window.
82477                                          */
82478
82479                                         emitcp = duk__lexer_parse_legacy_octal(lex_ctx, &adv, strict_mode /*reject_annex_b*/);
82480                                         if (emitcp < 0) {
82481                                                 goto fail_escape;
82482                                         }
82483                                 } else if (x < 0) {
82484                                         goto fail_unterminated;
82485                                 } else {
82486                                         /* escaped NonEscapeCharacter */
82487                                         DUK__APPENDBUFFER(lex_ctx, x);
82488                                 }
82489                         }  /* end default clause */
82490                         }  /* end switch */
82491
82492                         /* Shared handling for single codepoint escapes. */
82493                         if (emitcp >= 0) {
82494                                 DUK__APPENDBUFFER(lex_ctx, emitcp);
82495                         }
82496
82497                         /* Track number of escapes; count not really needed but directive
82498                          * prologues need to detect whether there were any escapes or line
82499                          * continuations or not.
82500                          */
82501                         out_token->num_escapes++;
82502                 } else if (x >= 0x20 && x <= 0x7f) {
82503                         /* Fast path for ASCII case, avoids line terminator
82504                          * check and CESU-8 encoding.
82505                          */
82506                         DUK_ASSERT(x >= 0);
82507                         DUK_ASSERT(!duk_unicode_is_line_terminator(x));
82508                         DUK_ASSERT(x != quote);
82509                         DUK_ASSERT(x != DUK_ASC_BACKSLASH);
82510                         DUK__APPENDBUFFER_ASCII(lex_ctx, x);
82511                 } else if (x < 0 || duk_unicode_is_line_terminator(x)) {
82512                         goto fail_unterminated;
82513                 } else {
82514                         /* Character which is part of the string but wasn't handled
82515                          * by the fast path.
82516                          */
82517                         DUK__APPENDBUFFER(lex_ctx, x);
82518                 }
82519         } /* string parse loop */
82520
82521         return;
82522
82523  fail_escape:
82524         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
82525         DUK_WO_NORETURN(return;);
82526
82527  fail_unterminated:
82528         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_STRING);
82529         DUK_WO_NORETURN(return;);
82530 }
82531
82532 /* Skip to end-of-line (or end-of-file), used for single line comments. */
82533 DUK_LOCAL void duk__lexer_skip_to_endofline(duk_lexer_ctx *lex_ctx) {
82534         for (;;) {
82535                 duk_codepoint_t x;
82536
82537                 x = DUK__L0();
82538                 if (x < 0 || duk_unicode_is_line_terminator(x)) {
82539                         break;
82540                 }
82541                 DUK__ADVANCECHARS(lex_ctx, 1);
82542         }
82543 }
82544
82545 /*
82546  *  Parse ECMAScript source InputElementDiv or InputElementRegExp
82547  *  (E5 Section 7), skipping whitespace, comments, and line terminators.
82548  *
82549  *  Possible results are:
82550  *    (1) a token
82551  *    (2) a line terminator (skipped)
82552  *    (3) a comment (skipped)
82553  *    (4) EOF
82554  *
82555  *  White space is automatically skipped from the current position (but
82556  *  not after the input element).  If input has already ended, returns
82557  *  DUK_TOK_EOF indefinitely.  If a parse error occurs, uses an DUK_ERROR()
82558  *  macro call (and hence a longjmp through current heap longjmp context).
82559  *  Comments and line terminator tokens are automatically skipped.
82560  *
82561  *  The input element being matched is determined by regexp_mode; if set,
82562  *  parses a InputElementRegExp, otherwise a InputElementDiv.  The
82563  *  difference between these are handling of productions starting with a
82564  *  forward slash.
82565  *
82566  *  If strict_mode is set, recognizes additional future reserved words
82567  *  specific to strict mode, and refuses to parse octal literals.
82568  *
82569  *  The matching strategy below is to (currently) use a six character
82570  *  lookup window to quickly determine which production is the -longest-
82571  *  matching one, and then parse that.  The top-level if-else clauses
82572  *  match the first character, and the code blocks for each clause
82573  *  handle -all- alternatives for that first character.  ECMAScript
82574  *  specification uses the "longest match wins" semantics, so the order
82575  *  of the if-clauses matters.
82576  *
82577  *  Misc notes:
82578  *
82579  *    * ECMAScript numeric literals do not accept a sign character.
82580  *      Consequently e.g. "-1.0" is parsed as two tokens: a negative
82581  *      sign and a positive numeric literal.  The compiler performs
82582  *      the negation during compilation, so this has no adverse impact.
82583  *
82584  *    * There is no token for "undefined": it is just a value available
82585  *      from the global object (or simply established by doing a reference
82586  *      to an undefined value).
82587  *
82588  *    * Some contexts want Identifier tokens, which are IdentifierNames
82589  *      excluding reserved words, while some contexts want IdentifierNames
82590  *      directly.  In the latter case e.g. "while" is interpreted as an
82591  *      identifier name, not a DUK_TOK_WHILE token.  The solution here is
82592  *      to provide both token types: DUK_TOK_WHILE goes to 't' while
82593  *      DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains
82594  *      the identifier / keyword name.
82595  *
82596  *    * Directive prologue needs to identify string literals such as
82597  *      "use strict" and 'use strict', which are sensitive to line
82598  *      continuations and escape sequences.  For instance, "use\u0020strict"
82599  *      is a valid directive but is distinct from "use strict".  The solution
82600  *      here is to decode escapes while tokenizing, but to keep track of the
82601  *      number of escapes.  Directive detection can then check that the
82602  *      number of escapes is zero.
82603  *
82604  *    * Multi-line comments with one or more internal LineTerminator are
82605  *      treated like a line terminator to comply with automatic semicolon
82606  *      insertion.
82607  */
82608
82609 DUK_INTERNAL
82610 void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
82611                                       duk_token *out_token,
82612                                       duk_bool_t strict_mode,
82613                                       duk_bool_t regexp_mode) {
82614         duk_codepoint_t x;           /* temporary, must be signed and 32-bit to hold Unicode code points */
82615         duk_small_uint_t advtok = 0; /* (advance << 8) + token_type, updated at function end,
82616                                       * init is unnecessary but suppresses "may be used uninitialized" warnings.
82617                                       */
82618         duk_bool_t got_lineterm = 0;  /* got lineterm preceding non-whitespace, non-lineterm token */
82619
82620         if (++lex_ctx->token_count >= lex_ctx->token_limit) {
82621                 goto fail_token_limit;
82622         }
82623
82624         out_token->t = DUK_TOK_EOF;
82625         out_token->t_nores = DUK_TOK_INVALID;  /* marker: copy t if not changed */
82626 #if 0  /* not necessary to init, disabled for faster parsing */
82627         out_token->num = DUK_DOUBLE_NAN;
82628         out_token->str1 = NULL;
82629         out_token->str2 = NULL;
82630 #endif
82631         out_token->num_escapes = 0;
82632         /* out_token->lineterm set by caller */
82633
82634         /* This would be nice, but parsing is faster without resetting the
82635          * value slots.  The only side effect is that references to temporary
82636          * string values may linger until lexing is finished; they're then
82637          * freed normally.
82638          */
82639 #if 0
82640         duk_to_undefined(lex_ctx->thr, lex_ctx->slot1_idx);
82641         duk_to_undefined(lex_ctx->thr, lex_ctx->slot2_idx);
82642 #endif
82643
82644         /* 'advtok' indicates how much to advance and which token id to assign
82645          * at the end.  This shared functionality minimizes code size.  All
82646          * code paths are required to set 'advtok' to some value, so no default
82647          * init value is used.  Code paths calling DUK_ERROR() never return so
82648          * they don't need to set advtok.
82649          */
82650
82651         /*
82652          *  Matching order:
82653          *
82654          *    Punctuator first chars, also covers comments, regexps
82655          *    LineTerminator
82656          *    Identifier or reserved word, also covers null/true/false literals
82657          *    NumericLiteral
82658          *    StringLiteral
82659          *    EOF
82660          *
82661          *  The order does not matter as long as the longest match is
82662          *  always correctly identified.  There are order dependencies
82663          *  in the clauses, so it's not trivial to convert to a switch.
82664          */
82665
82666  restart_lineupdate:
82667         out_token->start_line = lex_ctx->window[0].line;
82668
82669  restart:
82670         out_token->start_offset = lex_ctx->window[0].offset;
82671
82672         x = DUK__L0();
82673
82674         switch (x) {
82675         case DUK_ASC_SPACE:
82676         case DUK_ASC_HT:  /* fast paths for space and tab */
82677                 DUK__ADVANCECHARS(lex_ctx, 1);
82678                 goto restart;
82679         case DUK_ASC_LF:  /* LF line terminator; CR LF and Unicode lineterms are handled in slow path */
82680                 DUK__ADVANCECHARS(lex_ctx, 1);
82681                 got_lineterm = 1;
82682                 goto restart_lineupdate;
82683 #if defined(DUK_USE_SHEBANG_COMMENTS)
82684         case DUK_ASC_HASH:  /* '#' */
82685                 if (DUK__L1() == DUK_ASC_EXCLAMATION && lex_ctx->window[0].offset == 0 &&
82686                     (lex_ctx->flags & DUK_COMPILE_SHEBANG)) {
82687                         /* "Shebang" comment ('#! ...') on first line. */
82688                         /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */
82689                         duk__lexer_skip_to_endofline(lex_ctx);
82690                         goto restart;  /* line terminator will be handled on next round */
82691                 }
82692                 goto fail_token;
82693 #endif  /* DUK_USE_SHEBANG_COMMENTS */
82694         case DUK_ASC_SLASH:  /* '/' */
82695                 if (DUK__L1() == DUK_ASC_SLASH) {
82696                         /*
82697                          *  E5 Section 7.4, allow SourceCharacter (which is any 16-bit
82698                          *  code point).
82699                          */
82700
82701                         /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but not necessary */
82702                         duk__lexer_skip_to_endofline(lex_ctx);
82703                         goto restart;  /* line terminator will be handled on next round */
82704                 } else if (DUK__L1() == DUK_ASC_STAR) {
82705                         /*
82706                          *  E5 Section 7.4.  If the multi-line comment contains a newline,
82707                          *  it is treated like a single line terminator for automatic
82708                          *  semicolon insertion.
82709                          */
82710
82711                         duk_bool_t last_asterisk = 0;
82712                         DUK__ADVANCECHARS(lex_ctx, 2);
82713                         for (;;) {
82714                                 x = DUK__L0();
82715                                 if (x < 0) {
82716                                         goto fail_unterm_comment;
82717                                 }
82718                                 DUK__ADVANCECHARS(lex_ctx, 1);
82719                                 if (last_asterisk && x == DUK_ASC_SLASH) {
82720                                         break;
82721                                 }
82722                                 if (duk_unicode_is_line_terminator(x)) {
82723                                         got_lineterm = 1;
82724                                 }
82725                                 last_asterisk = (x == DUK_ASC_STAR);
82726                         }
82727                         goto restart_lineupdate;
82728                 } else if (regexp_mode) {
82729 #if defined(DUK_USE_REGEXP_SUPPORT)
82730                         /*
82731                          *  "/" followed by something in regexp mode.  See E5 Section 7.8.5.
82732                          *
82733                          *  RegExp parsing is a bit complex.  First, the regexp body is delimited
82734                          *  by forward slashes, but the body may also contain forward slashes as
82735                          *  part of an escape sequence or inside a character class (delimited by
82736                          *  square brackets).  A mini state machine is used to implement these.
82737                          *
82738                          *  Further, an early (parse time) error must be thrown if the regexp
82739                          *  would cause a run-time error when used in the expression new RegExp(...).
82740                          *  Parsing here simply extracts the (candidate) regexp, and also accepts
82741                          *  invalid regular expressions (which are delimited properly).  The caller
82742                          *  (compiler) must perform final validation and regexp compilation.
82743                          *
82744                          *  RegExp first char may not be '/' (single line comment) or '*' (multi-
82745                          *  line comment).  These have already been checked above, so there is no
82746                          *  need below for special handling of the first regexp character as in
82747                          *  the E5 productions.
82748                          *
82749                          *  About unicode escapes within regexp literals:
82750                          *
82751                          *      E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes.
82752                          *      However, Section 6 states that regexps accept the escapes,
82753                          *      see paragraph starting with "In string literals...".
82754                          *      The regexp grammar, which sees the decoded regexp literal
82755                          *      (after lexical parsing) DOES have a \uHHHH unicode escape.
82756                          *      So, for instance:
82757                          *
82758                          *          /\u1234/
82759                          *
82760                          *      should first be parsed by the lexical grammar as:
82761                          *
82762                          *          '\' 'u'      RegularExpressionBackslashSequence
82763                          *          '1'          RegularExpressionNonTerminator
82764                          *          '2'          RegularExpressionNonTerminator
82765                          *          '3'          RegularExpressionNonTerminator
82766                          *          '4'          RegularExpressionNonTerminator
82767                          *
82768                          *      and the escape itself is then parsed by the regexp engine.
82769                          *      This is the current implementation.
82770                          *
82771                          *  Minor spec inconsistency:
82772                          *
82773                          *      E5 Section 7.8.5 RegularExpressionBackslashSequence is:
82774                          *
82775                          *         \ RegularExpressionNonTerminator
82776                          *
82777                          *      while Section A.1 RegularExpressionBackslashSequence is:
82778                          *
82779                          *         \ NonTerminator
82780                          *
82781                          *      The latter is not normative and a typo.
82782                          *
82783                          */
82784
82785                         /* first, parse regexp body roughly */
82786
82787                         duk_small_int_t state = 0;  /* 0=base, 1=esc, 2=class, 3=class+esc */
82788
82789                         DUK__INITBUFFER(lex_ctx);
82790                         for (;;) {
82791                                 DUK__ADVANCECHARS(lex_ctx, 1);  /* skip opening slash on first loop */
82792                                 x = DUK__L0();
82793                                 if (x < 0 || duk_unicode_is_line_terminator(x)) {
82794                                         goto fail_unterm_regexp;
82795                                 }
82796                                 x = DUK__L0();  /* re-read to avoid spill / fetch */
82797                                 if (state == 0) {
82798                                         if (x == DUK_ASC_SLASH) {
82799                                                 DUK__ADVANCECHARS(lex_ctx, 1);  /* eat closing slash */
82800                                                 break;
82801                                         } else if (x == DUK_ASC_BACKSLASH) {
82802                                                 state = 1;
82803                                         } else if (x == DUK_ASC_LBRACKET) {
82804                                                 state = 2;
82805                                         }
82806                                 } else if (state == 1) {
82807                                         state = 0;
82808                                 } else if (state == 2) {
82809                                         if (x == DUK_ASC_RBRACKET) {
82810                                                 state = 0;
82811                                         } else if (x == DUK_ASC_BACKSLASH) {
82812                                                 state = 3;
82813                                         }
82814                                 } else { /* state == 3 */
82815                                         state = 2;
82816                                 }
82817                                 DUK__APPENDBUFFER(lex_ctx, x);
82818                         }
82819                         out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
82820
82821                         /* second, parse flags */
82822
82823                         DUK__INITBUFFER(lex_ctx);
82824                         for (;;) {
82825                                 x = DUK__L0();
82826                                 if (!duk_unicode_is_identifier_part(x)) {
82827                                         break;
82828                                 }
82829                                 x = DUK__L0();  /* re-read to avoid spill / fetch */
82830                                 DUK__APPENDBUFFER(lex_ctx, x);
82831                                 DUK__ADVANCECHARS(lex_ctx, 1);
82832                         }
82833                         out_token->str2 = duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
82834
82835                         DUK__INITBUFFER(lex_ctx);  /* free some memory */
82836
82837                         /* validation of the regexp is caller's responsibility */
82838
82839                         advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP);
82840 #else  /* DUK_USE_REGEXP_SUPPORT */
82841                         goto fail_regexp_support;
82842 #endif  /* DUK_USE_REGEXP_SUPPORT */
82843                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
82844                         /* "/=" and not in regexp mode */
82845                         advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ);
82846                 } else {
82847                         /* "/" and not in regexp mode */
82848                         advtok = DUK__ADVTOK(1, DUK_TOK_DIV);
82849                 }
82850                 break;
82851         case DUK_ASC_LCURLY:  /* '{' */
82852                 advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY);
82853                 break;
82854         case DUK_ASC_RCURLY:  /* '}' */
82855                 advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY);
82856                 break;
82857         case DUK_ASC_LPAREN:  /* '(' */
82858                 advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN);
82859                 break;
82860         case DUK_ASC_RPAREN:  /* ')' */
82861                 advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN);
82862                 break;
82863         case DUK_ASC_LBRACKET:  /* '[' */
82864                 advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET);
82865                 break;
82866         case DUK_ASC_RBRACKET:  /* ']' */
82867                 advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET);
82868                 break;
82869         case DUK_ASC_PERIOD:  /* '.' */
82870                 if (DUK__ISDIGIT(DUK__L1())) {
82871                         /* Period followed by a digit can only start DecimalLiteral
82872                          * (handled in slow path).  We could jump straight into the
82873                          * DecimalLiteral handling but should avoid goto to inside
82874                          * a block.
82875                          */
82876                         goto slow_path;
82877                 }
82878                 advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD);
82879                 break;
82880         case DUK_ASC_SEMICOLON:  /* ';' */
82881                 advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON);
82882                 break;
82883         case DUK_ASC_COMMA:  /* ',' */
82884                 advtok = DUK__ADVTOK(1, DUK_TOK_COMMA);
82885                 break;
82886         case DUK_ASC_LANGLE:  /* '<' */
82887 #if defined(DUK_USE_HTML_COMMENTS)
82888                 if (DUK__L1() == DUK_ASC_EXCLAMATION && DUK__L2() == DUK_ASC_MINUS && DUK__L3() == DUK_ASC_MINUS) {
82889                         /*
82890                          *  ES2015: B.1.3, handle "<!--" SingleLineHTMLOpenComment
82891                          */
82892
82893                         /* DUK__ADVANCECHARS(lex_ctx, 4) would be correct here, but not necessary */
82894                         duk__lexer_skip_to_endofline(lex_ctx);
82895                         goto restart;  /* line terminator will be handled on next round */
82896                 }
82897                 else
82898 #endif  /* DUK_USE_HTML_COMMENTS */
82899                 if (DUK__L1() == DUK_ASC_LANGLE && DUK__L2() == DUK_ASC_EQUALS) {
82900                         advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ);
82901                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
82902                         advtok = DUK__ADVTOK(2, DUK_TOK_LE);
82903                 } else if (DUK__L1() == DUK_ASC_LANGLE) {
82904                         advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT);
82905                 } else {
82906                         advtok = DUK__ADVTOK(1, DUK_TOK_LT);
82907                 }
82908                 break;
82909         case DUK_ASC_RANGLE:  /* '>' */
82910                 if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE && DUK__L3() == DUK_ASC_EQUALS) {
82911                         advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ);
82912                 } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE) {
82913                         advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT);
82914                 } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_EQUALS) {
82915                         advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ);
82916                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
82917                         advtok = DUK__ADVTOK(2, DUK_TOK_GE);
82918                 } else if (DUK__L1() == DUK_ASC_RANGLE) {
82919                         advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT);
82920                 } else {
82921                         advtok = DUK__ADVTOK(1, DUK_TOK_GT);
82922                 }
82923                 break;
82924         case DUK_ASC_EQUALS:  /* '=' */
82925                 if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) {
82926                         advtok = DUK__ADVTOK(3, DUK_TOK_SEQ);
82927                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
82928                         advtok = DUK__ADVTOK(2, DUK_TOK_EQ);
82929                 } else {
82930                         advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN);
82931                 }
82932                 break;
82933         case DUK_ASC_EXCLAMATION:  /* '!' */
82934                 if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) {
82935                         advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ);
82936                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
82937                         advtok = DUK__ADVTOK(2, DUK_TOK_NEQ);
82938                 } else {
82939                         advtok = DUK__ADVTOK(1, DUK_TOK_LNOT);
82940                 }
82941                 break;
82942         case DUK_ASC_PLUS:  /* '+' */
82943                 if (DUK__L1() == DUK_ASC_PLUS) {
82944                         advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT);
82945                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
82946                         advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ);
82947                 } else {
82948                         advtok = DUK__ADVTOK(1, DUK_TOK_ADD);
82949                 }
82950                 break;
82951         case DUK_ASC_MINUS:  /* '-' */
82952 #if defined(DUK_USE_HTML_COMMENTS)
82953                 if (got_lineterm && DUK__L1() == DUK_ASC_MINUS && DUK__L2() == DUK_ASC_RANGLE) {
82954                         /*
82955                          *  ES2015: B.1.3, handle "-->" SingleLineHTMLCloseComment
82956                          *  Only allowed:
82957                          *  - on new line
82958                          *  - preceded only by whitespace
82959                          *  - preceded by end of multiline comment and optional whitespace
82960                          *
82961                          * Since whitespace generates no tokens, and multiline comments
82962                          * are treated as a line ending, consulting `got_lineterm` is
82963                          * sufficient to test for these three options.
82964                          */
82965
82966                         /* DUK__ADVANCECHARS(lex_ctx, 3) would be correct here, but not necessary */
82967                         duk__lexer_skip_to_endofline(lex_ctx);
82968                         goto restart;  /* line terminator will be handled on next round */
82969                 } else
82970 #endif  /* DUK_USE_HTML_COMMENTS */
82971                 if (DUK__L1() == DUK_ASC_MINUS) {
82972                         advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT);
82973                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
82974                         advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ);
82975                 } else {
82976                         advtok = DUK__ADVTOK(1, DUK_TOK_SUB);
82977                 }
82978                 break;
82979         case DUK_ASC_STAR:  /* '*' */
82980 #if defined(DUK_USE_ES7_EXP_OPERATOR)
82981                 if (DUK__L1() == DUK_ASC_STAR && DUK__L2() == DUK_ASC_EQUALS) {
82982                         advtok = DUK__ADVTOK(3, DUK_TOK_EXP_EQ);
82983                 } else if (DUK__L1() == DUK_ASC_STAR) {
82984                         advtok = DUK__ADVTOK(2, DUK_TOK_EXP);
82985                 } else
82986 #endif
82987                 if (DUK__L1() == DUK_ASC_EQUALS) {
82988                         advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ);
82989                 } else {
82990                         advtok = DUK__ADVTOK(1, DUK_TOK_MUL);
82991                 }
82992                 break;
82993         case DUK_ASC_PERCENT:  /* '%' */
82994                 if (DUK__L1() == DUK_ASC_EQUALS) {
82995                         advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ);
82996                 } else {
82997                         advtok = DUK__ADVTOK(1, DUK_TOK_MOD);
82998                 }
82999                 break;
83000         case DUK_ASC_AMP:  /* '&' */
83001                 if (DUK__L1() == DUK_ASC_AMP) {
83002                         advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
83003                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
83004                         advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
83005                 } else {
83006                         advtok = DUK__ADVTOK(1, DUK_TOK_BAND);
83007                 }
83008                 break;
83009         case DUK_ASC_PIPE:  /* '|' */
83010                 if (DUK__L1() == DUK_ASC_PIPE) {
83011                         advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
83012                 } else if (DUK__L1() == DUK_ASC_EQUALS) {
83013                         advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
83014                 } else {
83015                         advtok = DUK__ADVTOK(1, DUK_TOK_BOR);
83016                 }
83017                 break;
83018         case DUK_ASC_CARET:  /* '^' */
83019                 if (DUK__L1() == DUK_ASC_EQUALS) {
83020                         advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ);
83021                 } else {
83022                         advtok = DUK__ADVTOK(1, DUK_TOK_BXOR);
83023                 }
83024                 break;
83025         case DUK_ASC_TILDE:  /* '~' */
83026                 advtok = DUK__ADVTOK(1, DUK_TOK_BNOT);
83027                 break;
83028         case DUK_ASC_QUESTION:  /* '?' */
83029                 advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION);
83030                 break;
83031         case DUK_ASC_COLON:  /* ':' */
83032                 advtok = DUK__ADVTOK(1, DUK_TOK_COLON);
83033                 break;
83034         case DUK_ASC_DOUBLEQUOTE:    /* '"' */
83035         case DUK_ASC_SINGLEQUOTE: {  /* '\'' */
83036                 DUK__INITBUFFER(lex_ctx);
83037                 duk__lexer_parse_string_literal(lex_ctx, out_token, x /*quote*/, strict_mode);
83038                 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
83039                 out_token->str1 = duk_known_hstring(lex_ctx->thr, lex_ctx->slot1_idx);
83040
83041                 DUK__INITBUFFER(lex_ctx);  /* free some memory */
83042
83043                 advtok = DUK__ADVTOK(0, DUK_TOK_STRING);
83044                 break;
83045         }
83046         default:
83047                 goto slow_path;
83048         }  /* switch */
83049
83050         goto skip_slow_path;
83051
83052  slow_path:
83053         if (duk_unicode_is_line_terminator(x)) {
83054                 if (x == 0x000d && DUK__L1() == 0x000a) {
83055                         /*
83056                          *  E5 Section 7.3: CR LF is detected as a single line terminator for
83057                          *  line numbers.  Here we also detect it as a single line terminator
83058                          *  token.
83059                          */
83060                         DUK__ADVANCECHARS(lex_ctx, 2);
83061                 } else {
83062                         DUK__ADVANCECHARS(lex_ctx, 1);
83063                 }
83064                 got_lineterm = 1;
83065                 goto restart_lineupdate;
83066         } else if (duk_unicode_is_identifier_start(x) || x == DUK_ASC_BACKSLASH) {
83067                 /*
83068                  *  Parse an identifier and then check whether it is:
83069                  *    - reserved word (keyword or other reserved word)
83070                  *    - "null"  (NullLiteral)
83071                  *    - "true"  (BooleanLiteral)
83072                  *    - "false" (BooleanLiteral)
83073                  *    - anything else => identifier
83074                  *
83075                  *  This does not follow the E5 productions cleanly, but is
83076                  *  useful and compact.
83077                  *
83078                  *  Note that identifiers may contain Unicode escapes,
83079                  *  see E5 Sections 6 and 7.6.  They must be decoded first,
83080                  *  and the result checked against allowed characters.
83081                  *  The above if-clause accepts an identifier start and an
83082                  *  '\' character -- no other token can begin with a '\'.
83083                  *
83084                  *  Note that "get" and "set" are not reserved words in E5
83085                  *  specification so they are recognized as plain identifiers
83086                  *  (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not
83087                  *  used now).  The compiler needs to work around this.
83088                  *
83089                  *  Strictly speaking, following ECMAScript longest match
83090                  *  specification, an invalid escape for the first character
83091                  *  should cause a syntax error.  However, an invalid escape
83092                  *  for IdentifierParts should just terminate the identifier
83093                  *  early (longest match), and let the next tokenization
83094                  *  fail.  For instance Rhino croaks with 'foo\z' when
83095                  *  parsing the identifier.  This has little practical impact.
83096                  */
83097
83098                 duk_small_uint_t i, i_end;
83099                 duk_bool_t first = 1;
83100                 duk_hstring *str;
83101
83102                 DUK__INITBUFFER(lex_ctx);
83103                 for (;;) {
83104                         /* re-lookup first char on first loop */
83105                         if (DUK__L0() == DUK_ASC_BACKSLASH) {
83106                                 duk_codepoint_t esc_cp;
83107                                 if (DUK__L1() != DUK_ASC_LC_U) {
83108                                         goto fail_escape;
83109                                 }
83110                                 esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/);
83111                                 DUK__APPENDBUFFER(lex_ctx, esc_cp);
83112
83113                                 /* IdentifierStart is stricter than IdentifierPart, so if the first
83114                                  * character is escaped, must have a stricter check here.
83115                                  */
83116                                 if (!(first ? duk_unicode_is_identifier_start(esc_cp) : duk_unicode_is_identifier_part(esc_cp))) {
83117                                         goto fail_escape;
83118                                 }
83119
83120                                 /* Track number of escapes: necessary for proper keyword
83121                                  * detection.
83122                                  */
83123                                 out_token->num_escapes++;
83124                         } else {
83125                                 /* Note: first character is checked against this.  But because
83126                                  * IdentifierPart includes all IdentifierStart characters, and
83127                                  * the first character (if unescaped) has already been checked
83128                                  * in the if condition, this is OK.
83129                                  */
83130                                 if (!duk_unicode_is_identifier_part(DUK__L0())) {
83131                                         break;
83132                                 }
83133                                 DUK__APPENDBUFFER(lex_ctx, DUK__L0());
83134                                 DUK__ADVANCECHARS(lex_ctx, 1);
83135                         }
83136                         first = 0;
83137                 }
83138
83139                 out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
83140                 str = out_token->str1;
83141                 out_token->t_nores = DUK_TOK_IDENTIFIER;
83142
83143                 DUK__INITBUFFER(lex_ctx);  /* free some memory */
83144
83145                 /*
83146                  *  Interned identifier is compared against reserved words, which are
83147                  *  currently interned into the heap context.  See genbuiltins.py.
83148                  *
83149                  *  Note that an escape in the identifier disables recognition of
83150                  *  keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to
83151                  *  identifier named "if").  This is not necessarily compliant,
83152                  *  see test-dec-escaped-char-in-keyword.js.
83153                  *
83154                  *  Note: "get" and "set" are awkward.  They are not officially
83155                  *  ReservedWords (and indeed e.g. "var set = 1;" is valid), and
83156                  *  must come out as DUK_TOK_IDENTIFIER.  The compiler needs to
83157                  *  work around this a bit.
83158                  */
83159
83160                 /* XXX: optimize by adding the token numbers directly into the
83161                  * always interned duk_hstring objects (there should be enough
83162                  * flag bits free for that)?
83163                  */
83164
83165                 i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED);
83166
83167                 advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
83168                 if (out_token->num_escapes == 0) {
83169                         for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
83170                                 DUK_ASSERT_DISABLE(i >= 0);  /* unsigned */
83171                                 DUK_ASSERT(i < DUK_HEAP_NUM_STRINGS);
83172                                 if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) {
83173                                         advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
83174                                         break;
83175                                 }
83176                         }
83177                 }
83178         } else if (DUK__ISDIGIT(x) || (x == DUK_ASC_PERIOD)) {
83179                 /* Note: decimal number may start with a period, but must be followed by a digit */
83180
83181                 /*
83182                  *  Pre-parsing for decimal, hex, octal (both legacy and ES2015),
83183                  *  and binary literals, followed by an actual parser step
83184                  *  provided by numconv.
83185                  *
83186                  *  Note: the leading sign character ('+' or '-') is -not- part of
83187                  *  the production in E5 grammar, and that the a DecimalLiteral
83188                  *  starting with a '0' must be followed by a non-digit.
83189                  *
83190                  *  XXX: the two step parsing process is quite awkward, it would
83191                  *  be more straightforward to allow numconv to parse the longest
83192                  *  valid prefix (it already does that, it only needs to indicate
83193                  *  where the input ended).  However, the lexer decodes characters
83194                  *  using a limited lookup window, so this is not a trivial change.
83195                  */
83196
83197                 /* XXX: because of the final check below (that the literal is not
83198                  * followed by a digit), this could maybe be simplified, if we bail
83199                  * out early from a leading zero (and if there are no periods etc).
83200                  * Maybe too complex.
83201                  */
83202
83203                 duk_double_t val;
83204                 duk_bool_t legacy_oct = 0;
83205                 duk_small_int_t state;  /* 0=before period/exp,
83206                                          * 1=after period, before exp
83207                                          * 2=after exp, allow '+' or '-'
83208                                          * 3=after exp and exp sign
83209                                          */
83210                 duk_small_uint_t s2n_flags;
83211                 duk_codepoint_t y, z;
83212                 duk_small_int_t s2n_radix = 10;
83213                 duk_small_uint_t pre_adv = 0;
83214
83215                 DUK__INITBUFFER(lex_ctx);
83216                 y = DUK__L1();
83217
83218                 if (x == DUK_ASC_0) {
83219                         z = DUK_LOWERCASE_CHAR_ASCII(y);
83220
83221                         pre_adv = 2;  /* default for 0xNNN, 0oNNN, 0bNNN. */
83222                         if (z == DUK_ASC_LC_X) {
83223                                 s2n_radix = 16;
83224                         } else if (z == DUK_ASC_LC_O) {
83225                                 s2n_radix = 8;
83226                         } else if (z == DUK_ASC_LC_B) {
83227                                 s2n_radix = 2;
83228                         } else {
83229                                 pre_adv = 0;
83230                                 if (DUK__ISDIGIT(y)) {
83231                                         if (strict_mode) {
83232                                                 /* Reject octal like \07 but also octal-lookalike
83233                                                  * decimal like \08 in strict mode.
83234                                                  */
83235                                                 goto fail_number_literal;
83236                                         } else {
83237                                                 /* Legacy OctalIntegerLiteral or octal-lookalice
83238                                                  * decimal.  Deciding between the two happens below
83239                                                  * in digit scanning.
83240                                                  */
83241                                                 DUK__APPENDBUFFER(lex_ctx, x);
83242                                                 pre_adv = 1;
83243                                                 legacy_oct = 1;
83244                                                 s2n_radix = 8;  /* tentative unless conflicting digits found */
83245                                         }
83246                                 }
83247                         }
83248                 }
83249
83250                 DUK__ADVANCECHARS(lex_ctx, pre_adv);
83251
83252                 /* XXX: we could parse integers here directly, and fall back
83253                  * to numconv only when encountering a fractional expression
83254                  * or when an octal literal turned out to be decimal (0778 etc).
83255                  */
83256                 state = 0;
83257                 for (;;) {
83258                         x = DUK__L0();  /* re-lookup curr char on first round */
83259                         if (DUK__ISDIGIT(x)) {
83260                                 /* Note: intentionally allow leading zeroes here, as the
83261                                  * actual parser will check for them.
83262                                  */
83263                                 if (state == 0 && legacy_oct && (x == DUK_ASC_8 || x == DUK_ASC_9)) {
83264                                         /* Started out as an octal-lookalike
83265                                          * but interpreted as decimal, e.g.
83266                                          * '0779' -> 779.  This also means
83267                                          * that fractions are allowed, e.g.
83268                                          * '0779.123' is allowed but '0777.123'
83269                                          * is not!
83270                                          */
83271                                         s2n_radix = 10;
83272                                 }
83273                                 if (state == 2) {
83274                                         state = 3;
83275                                 }
83276                         } else if (s2n_radix == 16 && DUK__ISHEXDIGIT(x)) {
83277                                 /* Note: 'e' and 'E' are also accepted here. */
83278                                 ;
83279                         } else if (x == DUK_ASC_PERIOD) {
83280                                 if (state >= 1 || s2n_radix != 10) {
83281                                         break;
83282                                 } else {
83283                                         state = 1;
83284                                 }
83285                         } else if (x == DUK_ASC_LC_E || x == DUK_ASC_UC_E) {
83286                                 if (state >= 2 || s2n_radix != 10) {
83287                                         break;
83288                                 } else {
83289                                         state = 2;
83290                                 }
83291                         } else if (x == DUK_ASC_MINUS || x == DUK_ASC_PLUS) {
83292                                 if (state != 2) {
83293                                         break;
83294                                 } else {
83295                                         state = 3;
83296                                 }
83297                         } else {
83298                                 break;
83299                         }
83300                         DUK__APPENDBUFFER(lex_ctx, x);
83301                         DUK__ADVANCECHARS(lex_ctx, 1);
83302                 }
83303
83304                 /* XXX: better coercion */
83305                 (void) duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
83306
83307                 if (s2n_radix != 10) {
83308                         /* For bases other than 10, integer only. */
83309                         s2n_flags = DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
83310                 } else {
83311                         s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
83312                                     DUK_S2N_FLAG_ALLOW_FRAC |
83313                                     DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
83314                                     DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
83315                                     DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
83316                 }
83317
83318                 duk_dup(lex_ctx->thr, lex_ctx->slot1_idx);
83319                 duk_numconv_parse(lex_ctx->thr, s2n_radix, s2n_flags);
83320                 val = duk_to_number_m1(lex_ctx->thr);
83321                 if (DUK_ISNAN(val)) {
83322                         goto fail_number_literal;
83323                 }
83324                 duk_replace(lex_ctx->thr, lex_ctx->slot1_idx);  /* could also just pop? */
83325
83326                 DUK__INITBUFFER(lex_ctx);  /* free some memory */
83327
83328                 /* Section 7.8.3 (note): NumericLiteral must be followed by something other than
83329                  * IdentifierStart or DecimalDigit.
83330                  */
83331
83332                 if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) {
83333                         goto fail_number_literal;
83334                 }
83335
83336                 out_token->num = val;
83337                 advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER);
83338         } else if (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) {
83339                 DUK__ADVANCECHARS(lex_ctx, 1);
83340                 goto restart;
83341         } else if (x < 0) {
83342                 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
83343         } else {
83344                 goto fail_token;
83345         }
83346  skip_slow_path:
83347
83348         /*
83349          *  Shared exit path
83350          */
83351
83352         DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
83353         out_token->t = advtok & 0xff;
83354         if (out_token->t_nores == DUK_TOK_INVALID) {
83355                 out_token->t_nores = out_token->t;
83356         }
83357         out_token->lineterm = got_lineterm;
83358
83359         /* Automatic semicolon insertion is allowed if a token is preceded
83360          * by line terminator(s), or terminates a statement list (right curly
83361          * or EOF).
83362          */
83363         if (got_lineterm || out_token->t == DUK_TOK_RCURLY || out_token->t == DUK_TOK_EOF) {
83364                 out_token->allow_auto_semi = 1;
83365         } else {
83366                 out_token->allow_auto_semi = 0;
83367         }
83368
83369         return;
83370
83371  fail_token_limit:
83372         DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT);
83373         DUK_WO_NORETURN(return;);
83374
83375  fail_token:
83376         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_TOKEN);
83377         DUK_WO_NORETURN(return;);
83378
83379  fail_number_literal:
83380         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_NUMBER_LITERAL);
83381         DUK_WO_NORETURN(return;);
83382
83383  fail_escape:
83384         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
83385         DUK_WO_NORETURN(return;);
83386
83387  fail_unterm_regexp:
83388         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_REGEXP);
83389         DUK_WO_NORETURN(return;);
83390
83391  fail_unterm_comment:
83392         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_COMMENT);
83393         DUK_WO_NORETURN(return;);
83394
83395 #if !defined(DUK_USE_REGEXP_SUPPORT)
83396  fail_regexp_support:
83397         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_REGEXP_SUPPORT_DISABLED);
83398         DUK_WO_NORETURN(return;);
83399 #endif
83400 }
83401
83402 #if defined(DUK_USE_REGEXP_SUPPORT)
83403
83404 /*
83405  *  Parse a RegExp token.  The grammar is described in E5 Section 15.10.
83406  *  Terminal constructions (such as quantifiers) are parsed directly here.
83407  *
83408  *  0xffffffffU is used as a marker for "infinity" in quantifiers.  Further,
83409  *  DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that
83410  *  will be accepted for a quantifier.
83411  */
83412
83413 DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
83414         duk_small_uint_t advtok = 0;  /* init is unnecessary but suppresses "may be used uninitialized" warnings */
83415         duk_codepoint_t x, y;
83416
83417         if (++lex_ctx->token_count >= lex_ctx->token_limit) {
83418                 goto fail_token_limit;
83419         }
83420
83421         duk_memzero(out_token, sizeof(*out_token));
83422
83423         x = DUK__L0();
83424         y = DUK__L1();
83425
83426         DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld", (long) x, (long) y));
83427
83428         switch (x) {
83429         case DUK_ASC_PIPE: {
83430                 advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION);
83431                 break;
83432         }
83433         case DUK_ASC_CARET: {
83434                 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START);
83435                 break;
83436         }
83437         case DUK_ASC_DOLLAR: {
83438                 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END);
83439                 break;
83440         }
83441         case DUK_ASC_QUESTION: {
83442                 out_token->qmin = 0;
83443                 out_token->qmax = 1;
83444                 if (y == DUK_ASC_QUESTION) {
83445                         advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
83446                         out_token->greedy = 0;
83447                 } else {
83448                         advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
83449                         out_token->greedy = 1;
83450                 }
83451                 break;
83452         }
83453         case DUK_ASC_STAR: {
83454                 out_token->qmin = 0;
83455                 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
83456                 if (y == DUK_ASC_QUESTION) {
83457                         advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
83458                         out_token->greedy = 0;
83459                 } else {
83460                         advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
83461                         out_token->greedy = 1;
83462                 }
83463                 break;
83464         }
83465         case DUK_ASC_PLUS: {
83466                 out_token->qmin = 1;
83467                 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
83468                 if (y == DUK_ASC_QUESTION) {
83469                         advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
83470                         out_token->greedy = 0;
83471                 } else {
83472                         advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
83473                         out_token->greedy = 1;
83474                 }
83475                 break;
83476         }
83477         case DUK_ASC_LCURLY: {
83478                 /* Production allows 'DecimalDigits', including leading zeroes */
83479                 duk_uint32_t val1 = 0;
83480                 duk_uint32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
83481                 duk_small_int_t digits = 0;
83482 #if defined(DUK_USE_ES6_REGEXP_SYNTAX)
83483                 duk_lexer_point lex_pt;
83484 #endif
83485
83486 #if defined(DUK_USE_ES6_REGEXP_SYNTAX)
83487                 /* Store lexer position, restoring if quantifier is invalid. */
83488                 DUK_LEXER_GETPOINT(lex_ctx, &lex_pt);
83489 #endif
83490
83491                 for (;;) {
83492                         DUK__ADVANCECHARS(lex_ctx, 1);  /* eat '{' on entry */
83493                         x = DUK__L0();
83494                         if (DUK__ISDIGIT(x)) {
83495                                 digits++;
83496                                 val1 = val1 * 10 + (duk_uint32_t) duk__hexval(x);
83497                         } else if (x == DUK_ASC_COMMA) {
83498                                 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
83499                                         goto invalid_quantifier;
83500                                 }
83501                                 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
83502                                         goto invalid_quantifier;
83503                                 }
83504                                 if (DUK__L1() == DUK_ASC_RCURLY) {
83505                                         /* form: { DecimalDigits , }, val1 = min count */
83506                                         if (digits == 0) {
83507                                                 goto invalid_quantifier;
83508                                         }
83509                                         out_token->qmin = val1;
83510                                         out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
83511                                         DUK__ADVANCECHARS(lex_ctx, 2);
83512                                         break;
83513                                 }
83514                                 val2 = val1;
83515                                 val1 = 0;
83516                                 digits = 0;  /* not strictly necessary because of lookahead '}' above */
83517                         } else if (x == DUK_ASC_RCURLY) {
83518                                 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
83519                                         goto invalid_quantifier;
83520                                 }
83521                                 if (digits == 0) {
83522                                         goto invalid_quantifier;
83523                                 }
83524                                 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
83525                                         /* val2 = min count, val1 = max count */
83526                                         out_token->qmin = val2;
83527                                         out_token->qmax = val1;
83528                                 } else {
83529                                         /* val1 = count */
83530                                         out_token->qmin = val1;
83531                                         out_token->qmax = val1;
83532                                 }
83533                                 DUK__ADVANCECHARS(lex_ctx, 1);
83534                                 break;
83535                         } else {
83536                                 goto invalid_quantifier;
83537                         }
83538                 }
83539                 if (DUK__L0() == DUK_ASC_QUESTION) {
83540                         out_token->greedy = 0;
83541                         DUK__ADVANCECHARS(lex_ctx, 1);
83542                 } else {
83543                         out_token->greedy = 1;
83544                 }
83545                 advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER);
83546                 break;
83547  invalid_quantifier:
83548 #if defined(DUK_USE_ES6_REGEXP_SYNTAX)
83549                 /* Failed to match the quantifier, restore lexer and parse
83550                  * opening brace as a literal.
83551                  */
83552                 DUK_LEXER_SETPOINT(lex_ctx, &lex_pt);
83553                 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
83554                 out_token->num = DUK_ASC_LCURLY;
83555 #else
83556                 goto fail_quantifier;
83557 #endif
83558                 break;
83559         }
83560         case DUK_ASC_PERIOD: {
83561                 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD);
83562                 break;
83563         }
83564         case DUK_ASC_BACKSLASH: {
83565                 /* The E5.1 specification does not seem to allow IdentifierPart characters
83566                  * to be used as identity escapes.  Unfortunately this includes '$', which
83567                  * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'.
83568                  * Many other implementations (including V8 and Rhino, for instance) do
83569                  * accept '\$' as a valid identity escape, which is quite pragmatic, and
83570                  * ES2015 Annex B relaxes the rules to allow these (and other) real world forms.
83571                  */
83572
83573                 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);  /* default: char escape (two chars) */
83574                 if (y == DUK_ASC_LC_B) {
83575                         advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY);
83576                 } else if (y == DUK_ASC_UC_B) {
83577                         advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY);
83578                 } else if (y == DUK_ASC_LC_F) {
83579                         out_token->num = 0x000c;
83580                 } else if (y == DUK_ASC_LC_N) {
83581                         out_token->num = 0x000a;
83582                 } else if (y == DUK_ASC_LC_T) {
83583                         out_token->num = 0x0009;
83584                 } else if (y == DUK_ASC_LC_R) {
83585                         out_token->num = 0x000d;
83586                 } else if (y == DUK_ASC_LC_V) {
83587                         out_token->num = 0x000b;
83588                 } else if (y == DUK_ASC_LC_C) {
83589                         x = DUK__L2();
83590                         if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
83591                             (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
83592                                 out_token->num = (duk_uint32_t) (x % 32);
83593                                 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
83594                         } else {
83595                                 goto fail_escape;
83596                         }
83597                 } else if (y == DUK_ASC_LC_X || y == DUK_ASC_LC_U) {
83598                         /* The token value is the Unicode codepoint without
83599                          * it being decode into surrogate pair characters
83600                          * here.  The \u{H+} is only allowed in Unicode mode
83601                          * which we don't support yet.
83602                          */
83603                         out_token->num = (duk_uint32_t) duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
83604                         advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_CHAR);
83605                 } else if (y == DUK_ASC_LC_D) {
83606                         advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
83607                 } else if (y == DUK_ASC_UC_D) {
83608                         advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT);
83609                 } else if (y == DUK_ASC_LC_S) {
83610                         advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE);
83611                 } else if (y == DUK_ASC_UC_S) {
83612                         advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE);
83613                 } else if (y == DUK_ASC_LC_W) {
83614                         advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR);
83615                 } else if (y == DUK_ASC_UC_W) {
83616                         advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR);
83617                 } else if (DUK__ISDIGIT(y)) {
83618                         /* E5 Section 15.10.2.11 */
83619                         if (y == DUK_ASC_0) {
83620                                 if (DUK__ISDIGIT(DUK__L2())) {
83621                                         goto fail_escape;
83622                                 }
83623                                 out_token->num = 0x0000;
83624                                 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
83625                         } else {
83626                                 /* XXX: shared parsing? */
83627                                 duk_uint32_t val = 0;
83628                                 duk_small_int_t i;
83629                                 for (i = 0; ; i++) {
83630                                         if (i >= DUK__MAX_RE_DECESC_DIGITS) {
83631                                                 goto fail_escape;
83632                                         }
83633                                         DUK__ADVANCECHARS(lex_ctx, 1);  /* eat backslash on entry */
83634                                         x = DUK__L0();
83635                                         if (!DUK__ISDIGIT(x)) {
83636                                                 break;
83637                                         }
83638                                         val = val * 10 + (duk_uint32_t) duk__hexval(x);
83639                                 }
83640                                 /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
83641                                 advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
83642                                 out_token->num = val;
83643                         }
83644 #if defined(DUK_USE_ES6_REGEXP_SYNTAX)
83645                 } else if (y >= 0) {
83646                         /* For ES2015 Annex B, accept any source character as identity
83647                          * escape except 'c' which is used for control characters.
83648                          * http://www.ecma-international.org/ecma-262/6.0/#sec-regular-expressions-patterns
83649                          * Careful not to match end-of-buffer (<0) here.
83650                          * This is not yet full ES2015 Annex B because cases above
83651                          * (like hex escape) won't backtrack.
83652                          */
83653                         DUK_ASSERT(y != DUK_ASC_LC_C);  /* covered above */
83654 #else  /* DUK_USE_ES6_REGEXP_SYNTAX */
83655                 } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) ||
83656                            y == DUK_UNICODE_CP_ZWNJ ||
83657                            y == DUK_UNICODE_CP_ZWJ) {
83658                         /* For ES5.1 identity escapes are not allowed for identifier
83659                          * parts.  This conflicts with a lot of real world code as this
83660                          * doesn't e.g. allow escaping a dollar sign as /\$/, see
83661                          * test-regexp-identity-escape-dollar.js.
83662                          */
83663 #endif  /* DUK_USE_ES6_REGEXP_SYNTAX */
83664                         out_token->num = (duk_uint32_t) y;
83665                 } else {
83666                         goto fail_escape;
83667                 }
83668                 break;
83669         }
83670         case DUK_ASC_LPAREN: {
83671                 /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */
83672
83673                 if (y == DUK_ASC_QUESTION) {
83674                         if (DUK__L2() == DUK_ASC_EQUALS) {
83675                                 /* (?= */
83676                                 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD);
83677                         } else if (DUK__L2() == DUK_ASC_EXCLAMATION) {
83678                                 /* (?! */
83679                                 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD);
83680                         } else if (DUK__L2() == DUK_ASC_COLON) {
83681                                 /* (?: */
83682                                 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP);
83683                         } else {
83684                                 goto fail_group;
83685                         }
83686                 } else {
83687                         /* ( */
83688                         advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP);
83689                 }
83690                 break;
83691         }
83692         case DUK_ASC_RPAREN: {
83693                 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP);
83694                 break;
83695         }
83696         case DUK_ASC_LBRACKET: {
83697                 /*
83698                  *  To avoid creating a heavy intermediate value for the list of ranges,
83699                  *  only the start token ('[' or '[^') is parsed here.  The regexp
83700                  *  compiler parses the ranges itself.
83701                  */
83702
83703                 /* XXX: with DUK_USE_ES6_REGEXP_SYNTAX we should allow left bracket
83704                  * literal too, but it's not easy to parse without backtracking.
83705                  */
83706
83707                 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS);
83708                 if (y == DUK_ASC_CARET) {
83709                         advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED);
83710                 }
83711                 break;
83712         }
83713 #if !defined(DUK_USE_ES6_REGEXP_SYNTAX)
83714         case DUK_ASC_RCURLY:
83715         case DUK_ASC_RBRACKET: {
83716                 /* Although these could be parsed as PatternCharacters unambiguously (here),
83717                  * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters.
83718                  */
83719                 goto fail_invalid_char;
83720                 break;
83721         }
83722 #endif
83723         case -1: {
83724                 /* EOF */
83725                 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
83726                 break;
83727         }
83728         default: {
83729                 /* PatternCharacter, all excluded characters are matched by cases above */
83730                 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
83731                 out_token->num = (duk_uint32_t) x;
83732                 break;
83733         }
83734         }
83735
83736         /*
83737          *  Shared exit path
83738          */
83739
83740         DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
83741         out_token->t = advtok & 0xff;
83742         return;
83743
83744  fail_token_limit:
83745         DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT);
83746         DUK_WO_NORETURN(return;);
83747
83748  fail_escape:
83749         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE);
83750         DUK_WO_NORETURN(return;);
83751
83752  fail_group:
83753         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_GROUP);
83754         DUK_WO_NORETURN(return;);
83755
83756 #if !defined(DUK_USE_ES6_REGEXP_SYNTAX)
83757  fail_invalid_char:
83758         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER);
83759         DUK_WO_NORETURN(return;);
83760
83761  fail_quantifier:
83762         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_QUANTIFIER);
83763         DUK_WO_NORETURN(return;);
83764 #endif
83765 }
83766
83767 /*
83768  *  Special parser for character classes; calls callback for every
83769  *  range parsed and returns the number of ranges present.
83770  */
83771
83772 /* XXX: this duplicates functionality in duk_regexp.c where a similar loop is
83773  * required anyway.  We could use that BUT we need to update the regexp compiler
83774  * 'nranges' too.  Work this out a bit more cleanly to save space.
83775  */
83776
83777 /* XXX: the handling of character range detection is a bit convoluted.
83778  * Try to simplify and make smaller.
83779  */
83780
83781 /* XXX: logic for handling character ranges is now incorrect, it will accept
83782  * e.g. [\d-z] whereas it should croak from it?  SMJS accepts this too, though.
83783  *
83784  * Needs a read through and a lot of additional tests.
83785  */
83786
83787 DUK_LOCAL
83788 void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx,
83789                                  duk_re_range_callback gen_range,
83790                                  void *userdata,
83791                                  const duk_uint16_t *ranges,
83792                                  duk_small_int_t num) {
83793         const duk_uint16_t *ranges_end;
83794
83795         DUK_UNREF(lex_ctx);
83796
83797         ranges_end = ranges + num;
83798         while (ranges < ranges_end) {
83799                 /* mark range 'direct', bypass canonicalization (see Wiki) */
83800                 gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1);
83801                 ranges += 2;
83802         }
83803 }
83804
83805 DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) {
83806         duk_codepoint_t start = -1;
83807         duk_codepoint_t ch;
83808         duk_codepoint_t x;
83809         duk_bool_t dash = 0;
83810         duk_small_uint_t adv = 0;
83811
83812         DUK_DD(DUK_DDPRINT("parsing regexp ranges"));
83813
83814         for (;;) {
83815                 DUK__ADVANCECHARS(lex_ctx, adv);
83816                 adv = 1;
83817
83818                 x = DUK__L0();
83819
83820                 ch = -1;  /* not strictly necessary, but avoids "uninitialized variable" warnings */
83821                 DUK_UNREF(ch);
83822
83823                 if (x < 0) {
83824                         goto fail_unterm_charclass;
83825                 } else if (x == DUK_ASC_RBRACKET) {
83826                         if (start >= 0) {
83827                                 gen_range(userdata, start, start, 0);
83828                         }
83829                         DUK__ADVANCECHARS(lex_ctx, 1);  /* eat ']' before finishing */
83830                         break;
83831                 } else if (x == DUK_ASC_MINUS) {
83832                         if (start >= 0 && !dash && DUK__L1() != DUK_ASC_RBRACKET) {
83833                                 /* '-' as a range indicator */
83834                                 dash = 1;
83835                                 continue;
83836                         } else {
83837                                 /* '-' verbatim */
83838                                 ch = x;
83839                         }
83840                 } else if (x == DUK_ASC_BACKSLASH) {
83841                         /*
83842                          *  The escapes are same as outside a character class, except that \b has a
83843                          *  different meaning, and \B and backreferences are prohibited (see E5
83844                          *  Section 15.10.2.19).  However, it's difficult to share code because we
83845                          *  handle e.g. "\n" very differently: here we generate a single character
83846                          *  range for it.
83847                          */
83848
83849                         /* XXX: ES2015 surrogate pair handling. */
83850
83851                         x = DUK__L1();
83852
83853                         adv = 2;
83854
83855                         if (x == DUK_ASC_LC_B) {
83856                                 /* Note: '\b' in char class is different than outside (assertion),
83857                                  * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part()
83858                                  * check below.
83859                                  */
83860                                 ch = 0x0008;
83861                         } else if (x == DUK_ASC_LC_F) {
83862                                 ch = 0x000c;
83863                         } else if (x == DUK_ASC_LC_N) {
83864                                 ch = 0x000a;
83865                         } else if (x == DUK_ASC_LC_T) {
83866                                 ch = 0x0009;
83867                         } else if (x == DUK_ASC_LC_R) {
83868                                 ch = 0x000d;
83869                         } else if (x == DUK_ASC_LC_V) {
83870                                 ch = 0x000b;
83871                         } else if (x == DUK_ASC_LC_C) {
83872                                 x = DUK__L2();
83873                                 adv = 3;
83874                                 if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
83875                                     (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
83876                                         ch = (x % 32);
83877                                 } else {
83878                                         goto fail_escape;
83879                                 }
83880                         } else if (x == DUK_ASC_LC_X || x == DUK_ASC_LC_U) {
83881                                 /* The \u{H+} form is only allowed in Unicode mode which
83882                                  * we don't support yet.
83883                                  */
83884                                 ch = duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
83885                                 adv = 0;
83886                         } else if (x == DUK_ASC_LC_D) {
83887                                 duk__emit_u16_direct_ranges(lex_ctx,
83888                                                             gen_range,
83889                                                             userdata,
83890                                                             duk_unicode_re_ranges_digit,
83891                                                             sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
83892                                 ch = -1;
83893                         } else if (x == DUK_ASC_UC_D) {
83894                                 duk__emit_u16_direct_ranges(lex_ctx,
83895                                                             gen_range,
83896                                                             userdata,
83897                                                             duk_unicode_re_ranges_not_digit,
83898                                                             sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t));
83899                                 ch = -1;
83900                         } else if (x == DUK_ASC_LC_S) {
83901                                 duk__emit_u16_direct_ranges(lex_ctx,
83902                                                             gen_range,
83903                                                             userdata,
83904                                                             duk_unicode_re_ranges_white,
83905                                                             sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
83906                                 ch = -1;
83907                         } else if (x == DUK_ASC_UC_S) {
83908                                 duk__emit_u16_direct_ranges(lex_ctx,
83909                                                             gen_range,
83910                                                             userdata,
83911                                                             duk_unicode_re_ranges_not_white,
83912                                                             sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t));
83913                                 ch = -1;
83914                         } else if (x == DUK_ASC_LC_W) {
83915                                 duk__emit_u16_direct_ranges(lex_ctx,
83916                                                             gen_range,
83917                                                             userdata,
83918                                                             duk_unicode_re_ranges_wordchar,
83919                                                             sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
83920                                 ch = -1;
83921                         } else if (x == DUK_ASC_UC_W) {
83922                                 duk__emit_u16_direct_ranges(lex_ctx,
83923                                                             gen_range,
83924                                                             userdata,
83925                                                             duk_unicode_re_ranges_not_wordchar,
83926                                                             sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t));
83927                                 ch = -1;
83928                         } else if (DUK__ISDIGIT(x)) {
83929                                 /* DecimalEscape, only \0 is allowed, no leading
83930                                  * zeroes are allowed.
83931                                  *
83932                                  * ES2015 Annex B also allows (maximal match) legacy
83933                                  * octal escapes up to \377 and \8 and \9 are
83934                                  * accepted as literal '8' and '9', also in strict mode.
83935                                  */
83936
83937 #if defined(DUK_USE_ES6_REGEXP_SYNTAX)
83938                                 ch = duk__lexer_parse_legacy_octal(lex_ctx, &adv, 0 /*reject_annex_b*/);
83939                                 DUK_ASSERT(ch >= 0);  /* no rejections */
83940 #else
83941                                 if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) {
83942                                         ch = 0x0000;
83943                                 } else {
83944                                         goto fail_escape;
83945                                 }
83946 #endif
83947 #if defined(DUK_USE_ES6_REGEXP_SYNTAX)
83948                         } else if (x >= 0) {
83949                                 /* IdentityEscape: ES2015 Annex B allows almost all
83950                                  * source characters here.  Match anything except
83951                                  * EOF here.
83952                                  */
83953                                 ch = x;
83954 #else  /* DUK_USE_ES6_REGEXP_SYNTAX */
83955                         } else if (!duk_unicode_is_identifier_part(x)) {
83956                                 /* IdentityEscape: ES5.1 doesn't allow identity escape
83957                                  * for identifier part characters, which conflicts with
83958                                  * some real world code.  For example, it doesn't allow
83959                                  * /[\$]/ which is awkward.
83960                                  */
83961                                 ch = x;
83962 #endif  /* DUK_USE_ES6_REGEXP_SYNTAX */
83963                         } else {
83964                                 goto fail_escape;
83965                         }
83966                 } else {
83967                         /* character represents itself */
83968                         ch = x;
83969                 }
83970
83971                 /* ch is a literal character here or -1 if parsed entity was
83972                  * an escape such as "\s".
83973                  */
83974
83975                 if (ch < 0) {
83976                         /* multi-character sets not allowed as part of ranges, see
83977                          * E5 Section 15.10.2.15, abstract operation CharacterRange.
83978                          */
83979                         if (start >= 0) {
83980                                 if (dash) {
83981                                         goto fail_range;
83982                                 } else {
83983                                         gen_range(userdata, start, start, 0);
83984                                         start = -1;
83985                                         /* dash is already 0 */
83986                                 }
83987                         }
83988                 } else {
83989                         if (start >= 0) {
83990                                 if (dash) {
83991                                         if (start > ch) {
83992                                                 goto fail_range;
83993                                         }
83994                                         gen_range(userdata, start, ch, 0);
83995                                         start = -1;
83996                                         dash = 0;
83997                                 } else {
83998                                         gen_range(userdata, start, start, 0);
83999                                         start = ch;
84000                                         /* dash is already 0 */
84001                                 }
84002                         } else {
84003                                 start = ch;
84004                         }
84005                 }
84006         }
84007
84008         return;
84009
84010  fail_escape:
84011         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE);
84012         DUK_WO_NORETURN(return;);
84013
84014  fail_range:
84015         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_RANGE);
84016         DUK_WO_NORETURN(return;);
84017
84018  fail_unterm_charclass:
84019         DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_CHARCLASS);
84020         DUK_WO_NORETURN(return;);
84021 }
84022
84023 #endif  /* DUK_USE_REGEXP_SUPPORT */
84024
84025 /* automatic undefs */
84026 #undef DUK__ADVANCEBYTES
84027 #undef DUK__ADVANCECHARS
84028 #undef DUK__ADVTOK
84029 #undef DUK__APPENDBUFFER
84030 #undef DUK__APPENDBUFFER_ASCII
84031 #undef DUK__INITBUFFER
84032 #undef DUK__ISDIGIT
84033 #undef DUK__ISDIGIT03
84034 #undef DUK__ISDIGIT47
84035 #undef DUK__ISHEXDIGIT
84036 #undef DUK__ISOCTDIGIT
84037 #undef DUK__L0
84038 #undef DUK__L1
84039 #undef DUK__L2
84040 #undef DUK__L3
84041 #undef DUK__L4
84042 #undef DUK__L5
84043 #undef DUK__LOOKUP
84044 #undef DUK__MAX_RE_DECESC_DIGITS
84045 #undef DUK__MAX_RE_QUANT_DIGITS
84046 #line 1 "duk_numconv.c"
84047 /*
84048  *  Number-to-string and string-to-number conversions.
84049  *
84050  *  Slow path number-to-string and string-to-number conversion is based on
84051  *  a Dragon4 variant, with fast paths for small integers.  Big integer
84052  *  arithmetic is needed for guaranteeing that the conversion is correct
84053  *  and uses a minimum number of digits.  The big number arithmetic has a
84054  *  fixed maximum size and does not require dynamic allocations.
84055  *
84056  *  See: doc/number-conversion.rst.
84057  */
84058
84059 /* #include duk_internal.h -> already included */
84060
84061 #define DUK__IEEE_DOUBLE_EXP_BIAS  1023
84062 #define DUK__IEEE_DOUBLE_EXP_MIN   (-1022)   /* biased exp == 0 -> denormal, exp -1022 */
84063
84064 #define DUK__DIGITCHAR(x)  duk_lc_digits[(x)]
84065
84066 /*
84067  *  Tables generated with util/gennumdigits.py.
84068  *
84069  *  duk__str2num_digits_for_radix indicates, for each radix, how many input
84070  *  digits should be considered significant for string-to-number conversion.
84071  *  The input is also padded to this many digits to give the Dragon4
84072  *  conversion enough (apparent) precision to work with.
84073  *
84074  *  duk__str2num_exp_limits indicates, for each radix, the radix-specific
84075  *  minimum/maximum exponent values (for a Dragon4 integer mantissa)
84076  *  below and above which the number is guaranteed to underflow to zero
84077  *  or overflow to Infinity.  This allows parsing to keep bigint values
84078  *  bounded.
84079  */
84080
84081 DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[] = {
84082         69, 44, 35, 30, 27, 25, 23, 22, 20, 20,    /* 2 to 11 */
84083         20, 19, 19, 18, 18, 17, 17, 17, 16, 16,    /* 12 to 21 */
84084         16, 16, 16, 15, 15, 15, 15, 15, 15, 14,    /* 22 to 31 */
84085         14, 14, 14, 14, 14                         /* 31 to 36 */
84086 };
84087
84088 typedef struct {
84089         duk_int16_t upper;
84090         duk_int16_t lower;
84091 } duk__exp_limits;
84092
84093 DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = {
84094         { 957, -1147 }, { 605, -725 },  { 479, -575 },  { 414, -496 },
84095         { 372, -446 },  { 342, -411 },  { 321, -384 },  { 304, -364 },
84096         { 291, -346 },  { 279, -334 },  { 268, -323 },  { 260, -312 },
84097         { 252, -304 },  { 247, -296 },  { 240, -289 },  { 236, -283 },
84098         { 231, -278 },  { 227, -273 },  { 223, -267 },  { 220, -263 },
84099         { 216, -260 },  { 213, -256 },  { 210, -253 },  { 208, -249 },
84100         { 205, -246 },  { 203, -244 },  { 201, -241 },  { 198, -239 },
84101         { 196, -237 },  { 195, -234 },  { 193, -232 },  { 191, -230 },
84102         { 190, -228 },  { 188, -226 },  { 187, -225 },
84103 };
84104
84105 /*
84106  *  Limited functionality bigint implementation.
84107  *
84108  *  Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits,
84109  *  with the caller responsible for ensuring this is never exceeded.  No memory
84110  *  allocation (except stack) is needed for bigint computation.  Operations
84111  *  have been tailored for number conversion needs.
84112  *
84113  *  Argument order is "assignment order", i.e. target first, then arguments:
84114  *  x <- y * z  -->  duk__bi_mul(x, y, z);
84115  */
84116
84117 /* This upper value has been experimentally determined; debug build will check
84118  * bigint size with assertions.
84119  */
84120 #define DUK__BI_MAX_PARTS  37  /* 37x32 = 1184 bits */
84121
84122 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
84123 #define DUK__BI_PRINT(name,x)  duk__bi_print((name),(x))
84124 #else
84125 #define DUK__BI_PRINT(name,x)
84126 #endif
84127
84128 /* Current size is about 152 bytes. */
84129 typedef struct {
84130         duk_small_int_t n;
84131         duk_uint32_t v[DUK__BI_MAX_PARTS];  /* low to high */
84132 } duk__bigint;
84133
84134 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
84135 DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) {
84136         /* Overestimate required size; debug code so not critical to be tight. */
84137         char buf[DUK__BI_MAX_PARTS * 9 + 64];
84138         char *p = buf;
84139         duk_small_int_t i;
84140
84141         /* No NUL term checks in this debug code. */
84142         p += DUK_SPRINTF(p, "%p n=%ld", (void *) x, (long) x->n);
84143         if (x->n == 0) {
84144                 p += DUK_SPRINTF(p, " 0");
84145         }
84146         for (i = x->n - 1; i >= 0; i--) {
84147                 p += DUK_SPRINTF(p, " %08lx", (unsigned long) x->v[i]);
84148         }
84149
84150         DUK_DDD(DUK_DDDPRINT("%s: %s", (const char *) name, (const char *) buf));
84151 }
84152 #endif
84153
84154 #if defined(DUK_USE_ASSERTIONS)
84155 DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) {
84156         return (duk_small_int_t)
84157                ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ &&
84158                  ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ );
84159 }
84160 #endif
84161
84162 DUK_LOCAL void duk__bi_normalize(duk__bigint *x) {
84163         duk_small_int_t i;
84164
84165         for (i = x->n - 1; i >= 0; i--) {
84166                 if (x->v[i] != 0) {
84167                         break;
84168                 }
84169         }
84170
84171         /* Note: if 'x' is zero, x->n becomes 0 here */
84172         x->n = i + 1;
84173         DUK_ASSERT(duk__bi_is_valid(x));
84174 }
84175
84176 /* x <- y */
84177 DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
84178         duk_small_int_t n;
84179
84180         n = y->n;
84181         x->n = n;
84182         /* No need to special case n == 0. */
84183         duk_memcpy((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * (size_t) n));
84184 }
84185
84186 DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
84187         if (v == 0U) {
84188                 x->n = 0;
84189         } else {
84190                 x->n = 1;
84191                 x->v[0] = v;
84192         }
84193         DUK_ASSERT(duk__bi_is_valid(x));
84194 }
84195
84196 /* Return value: <0  <=>  x < y
84197  *                0  <=>  x == y
84198  *               >0  <=>  x > y
84199  */
84200 DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) {
84201         duk_small_int_t i, nx, ny;
84202         duk_uint32_t tx, ty;
84203
84204         DUK_ASSERT(duk__bi_is_valid(x));
84205         DUK_ASSERT(duk__bi_is_valid(y));
84206
84207         nx = x->n;
84208         ny = y->n;
84209         if (nx > ny) {
84210                 goto ret_gt;
84211         }
84212         if (nx < ny) {
84213                 goto ret_lt;
84214         }
84215         for (i = nx - 1; i >= 0; i--) {
84216                 tx = x->v[i];
84217                 ty = y->v[i];
84218
84219                 if (tx > ty) {
84220                         goto ret_gt;
84221                 }
84222                 if (tx < ty) {
84223                         goto ret_lt;
84224                 }
84225         }
84226
84227         return 0;
84228
84229  ret_gt:
84230         return 1;
84231
84232  ret_lt:
84233         return -1;
84234 }
84235
84236 /* x <- y + z */
84237 #if defined(DUK_USE_64BIT_OPS)
84238 DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
84239         duk_uint64_t tmp;
84240         duk_small_int_t i, ny, nz;
84241
84242         DUK_ASSERT(duk__bi_is_valid(y));
84243         DUK_ASSERT(duk__bi_is_valid(z));
84244
84245         if (z->n > y->n) {
84246                 duk__bigint *t;
84247                 t = y; y = z; z = t;
84248         }
84249         DUK_ASSERT(y->n >= z->n);
84250
84251         ny = y->n; nz = z->n;
84252         tmp = 0U;
84253         for (i = 0; i < ny; i++) {
84254                 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
84255                 tmp += y->v[i];
84256                 if (i < nz) {
84257                         tmp += z->v[i];
84258                 }
84259                 x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
84260                 tmp = tmp >> 32;
84261         }
84262         if (tmp != 0U) {
84263                 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
84264                 x->v[i++] = (duk_uint32_t) tmp;
84265         }
84266         x->n = i;
84267         DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
84268
84269         /* no need to normalize */
84270         DUK_ASSERT(duk__bi_is_valid(x));
84271 }
84272 #else  /* DUK_USE_64BIT_OPS */
84273 DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
84274         duk_uint32_t carry, tmp1, tmp2;
84275         duk_small_int_t i, ny, nz;
84276
84277         DUK_ASSERT(duk__bi_is_valid(y));
84278         DUK_ASSERT(duk__bi_is_valid(z));
84279
84280         if (z->n > y->n) {
84281                 duk__bigint *t;
84282                 t = y; y = z; z = t;
84283         }
84284         DUK_ASSERT(y->n >= z->n);
84285
84286         ny = y->n; nz = z->n;
84287         carry = 0U;
84288         for (i = 0; i < ny; i++) {
84289                 /* Carry is detected based on wrapping which relies on exact 32-bit
84290                  * types.
84291                  */
84292                 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
84293                 tmp1 = y->v[i];
84294                 tmp2 = tmp1;
84295                 if (i < nz) {
84296                         tmp2 += z->v[i];
84297                 }
84298
84299                 /* Careful with carry condition:
84300                  *  - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678)
84301                  *  - If carry added:     0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678)
84302                  */
84303                 if (carry) {
84304                         tmp2++;
84305                         carry = (tmp2 <= tmp1 ? 1U : 0U);
84306                 } else {
84307                         carry = (tmp2 < tmp1 ? 1U : 0U);
84308                 }
84309
84310                 x->v[i] = tmp2;
84311         }
84312         if (carry) {
84313                 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
84314                 DUK_ASSERT(carry == 1U);
84315                 x->v[i++] = carry;
84316         }
84317         x->n = i;
84318         DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
84319
84320         /* no need to normalize */
84321         DUK_ASSERT(duk__bi_is_valid(x));
84322 }
84323 #endif  /* DUK_USE_64BIT_OPS */
84324
84325 /* x <- y + z */
84326 DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
84327         duk__bigint tmp;
84328
84329         DUK_ASSERT(duk__bi_is_valid(y));
84330
84331         /* XXX: this could be optimized; there is only one call site now though */
84332         duk__bi_set_small(&tmp, z);
84333         duk__bi_add(x, y, &tmp);
84334
84335         DUK_ASSERT(duk__bi_is_valid(x));
84336 }
84337
84338 #if 0  /* unused */
84339 /* x <- x + y, use t as temp */
84340 DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
84341         duk__bi_add(t, x, y);
84342         duk__bi_copy(x, t);
84343 }
84344 #endif
84345
84346 /* x <- y - z, require x >= y => z >= 0, i.e. y >= z */
84347 #if defined(DUK_USE_64BIT_OPS)
84348 DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
84349         duk_small_int_t i, ny, nz;
84350         duk_uint32_t ty, tz;
84351         duk_int64_t tmp;
84352
84353         DUK_ASSERT(duk__bi_is_valid(y));
84354         DUK_ASSERT(duk__bi_is_valid(z));
84355         DUK_ASSERT(duk__bi_compare(y, z) >= 0);
84356         DUK_ASSERT(y->n >= z->n);
84357
84358         ny = y->n; nz = z->n;
84359         tmp = 0;
84360         for (i = 0; i < ny; i++) {
84361                 ty = y->v[i];
84362                 if (i < nz) {
84363                         tz = z->v[i];
84364                 } else {
84365                         tz = 0;
84366                 }
84367                 tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp;
84368                 x->v[i] = (duk_uint32_t) ((duk_uint64_t) tmp & 0xffffffffUL);
84369                 tmp = tmp >> 32;  /* 0 or -1 */
84370         }
84371         DUK_ASSERT(tmp == 0);
84372
84373         x->n = i;
84374         duk__bi_normalize(x);  /* need to normalize, may even cancel to 0 */
84375         DUK_ASSERT(duk__bi_is_valid(x));
84376 }
84377 #else
84378 DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
84379         duk_small_int_t i, ny, nz;
84380         duk_uint32_t tmp1, tmp2, borrow;
84381
84382         DUK_ASSERT(duk__bi_is_valid(y));
84383         DUK_ASSERT(duk__bi_is_valid(z));
84384         DUK_ASSERT(duk__bi_compare(y, z) >= 0);
84385         DUK_ASSERT(y->n >= z->n);
84386
84387         ny = y->n; nz = z->n;
84388         borrow = 0U;
84389         for (i = 0; i < ny; i++) {
84390                 /* Borrow is detected based on wrapping which relies on exact 32-bit
84391                  * types.
84392                  */
84393                 tmp1 = y->v[i];
84394                 tmp2 = tmp1;
84395                 if (i < nz) {
84396                         tmp2 -= z->v[i];
84397                 }
84398
84399                 /* Careful with borrow condition:
84400                  *  - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678)
84401                  *  - If borrow subtracted:     0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678)
84402                  */
84403                 if (borrow) {
84404                         tmp2--;
84405                         borrow = (tmp2 >= tmp1 ? 1U : 0U);
84406                 } else {
84407                         borrow = (tmp2 > tmp1 ? 1U : 0U);
84408                 }
84409
84410                 x->v[i] = tmp2;
84411         }
84412         DUK_ASSERT(borrow == 0U);
84413
84414         x->n = i;
84415         duk__bi_normalize(x);  /* need to normalize, may even cancel to 0 */
84416         DUK_ASSERT(duk__bi_is_valid(x));
84417 }
84418 #endif
84419
84420 #if 0  /* unused */
84421 /* x <- y - z */
84422 DUK_LOCAL void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
84423         duk__bigint tmp;
84424
84425         DUK_ASSERT(duk__bi_is_valid(y));
84426
84427         /* XXX: this could be optimized */
84428         duk__bi_set_small(&tmp, z);
84429         duk__bi_sub(x, y, &tmp);
84430
84431         DUK_ASSERT(duk__bi_is_valid(x));
84432 }
84433 #endif
84434
84435 /* x <- x - y, use t as temp */
84436 DUK_LOCAL void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
84437         duk__bi_sub(t, x, y);
84438         duk__bi_copy(x, t);
84439 }
84440
84441 /* x <- y * z */
84442 DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
84443         duk_small_int_t i, j, nx, nz;
84444
84445         DUK_ASSERT(duk__bi_is_valid(y));
84446         DUK_ASSERT(duk__bi_is_valid(z));
84447
84448         nx = y->n + z->n;  /* max possible */
84449         DUK_ASSERT(nx <= DUK__BI_MAX_PARTS);
84450
84451         if (nx == 0) {
84452                 /* Both inputs are zero; cases where only one is zero can go
84453                  * through main algorithm.
84454                  */
84455                 x->n = 0;
84456                 return;
84457         }
84458
84459         duk_memzero((void *) x->v, (size_t) (sizeof(duk_uint32_t) * (size_t) nx));
84460         x->n = nx;
84461
84462         nz = z->n;
84463         for (i = 0; i < y->n; i++) {
84464 #if defined(DUK_USE_64BIT_OPS)
84465                 duk_uint64_t tmp = 0U;
84466                 for (j = 0; j < nz; j++) {
84467                         tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j];
84468                         x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL);
84469                         tmp = tmp >> 32;
84470                 }
84471                 if (tmp > 0) {
84472                         DUK_ASSERT(i + j < nx);
84473                         DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
84474                         DUK_ASSERT(x->v[i+j] == 0U);
84475                         x->v[i+j] = (duk_uint32_t) tmp;
84476                 }
84477 #else
84478                 /*
84479                  *  Multiply + add + carry for 32-bit components using only 16x16->32
84480                  *  multiplies and carry detection based on unsigned overflow.
84481                  *
84482                  *    1st mult, 32-bit: (A*2^16 + B)
84483                  *    2nd mult, 32-bit: (C*2^16 + D)
84484                  *    3rd add, 32-bit: E
84485                  *    4th add, 32-bit: F
84486                  *
84487                  *      (AC*2^16 + B) * (C*2^16 + D) + E + F
84488                  *    = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F
84489                  *    = AC*2^32 + (AD + BC)*2^16 + (BD + E + F)
84490                  *    = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F)
84491                  */
84492                 duk_uint32_t a, b, c, d, e, f;
84493                 duk_uint32_t r, s, t;
84494
84495                 a = y->v[i]; b = a & 0xffffUL; a = a >> 16;
84496
84497                 f = 0;
84498                 for (j = 0; j < nz; j++) {
84499                         c = z->v[j]; d = c & 0xffffUL; c = c >> 16;
84500                         e = x->v[i+j];
84501
84502                         /* build result as: (r << 32) + s: start with (BD + E + F) */
84503                         r = 0;
84504                         s = b * d;
84505
84506                         /* add E */
84507                         t = s + e;
84508                         if (t < s) { r++; }  /* carry */
84509                         s = t;
84510
84511                         /* add F */
84512                         t = s + f;
84513                         if (t < s) { r++; }  /* carry */
84514                         s = t;
84515
84516                         /* add BC*2^16 */
84517                         t = b * c;
84518                         r += (t >> 16);
84519                         t = s + ((t & 0xffffUL) << 16);
84520                         if (t < s) { r++; }  /* carry */
84521                         s = t;
84522
84523                         /* add AD*2^16 */
84524                         t = a * d;
84525                         r += (t >> 16);
84526                         t = s + ((t & 0xffffUL) << 16);
84527                         if (t < s) { r++; }  /* carry */
84528                         s = t;
84529
84530                         /* add AC*2^32 */
84531                         t = a * c;
84532                         r += t;
84533
84534                         DUK_DDD(DUK_DDDPRINT("ab=%08lx cd=%08lx ef=%08lx -> rs=%08lx %08lx",
84535                                              (unsigned long) y->v[i], (unsigned long) z->v[j],
84536                                              (unsigned long) x->v[i+j], (unsigned long) r,
84537                                              (unsigned long) s));
84538
84539                         x->v[i+j] = s;
84540                         f = r;
84541                 }
84542                 if (f > 0U) {
84543                         DUK_ASSERT(i + j < nx);
84544                         DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
84545                         DUK_ASSERT(x->v[i+j] == 0U);
84546                         x->v[i+j] = (duk_uint32_t) f;
84547                 }
84548 #endif  /* DUK_USE_64BIT_OPS */
84549         }
84550
84551         duk__bi_normalize(x);
84552         DUK_ASSERT(duk__bi_is_valid(x));
84553 }
84554
84555 /* x <- y * z */
84556 DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
84557         duk__bigint tmp;
84558
84559         DUK_ASSERT(duk__bi_is_valid(y));
84560
84561         /* XXX: this could be optimized */
84562         duk__bi_set_small(&tmp, z);
84563         duk__bi_mul(x, y, &tmp);
84564
84565         DUK_ASSERT(duk__bi_is_valid(x));
84566 }
84567
84568 /* x <- x * y, use t as temp */
84569 DUK_LOCAL void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
84570         duk__bi_mul(t, x, y);
84571         duk__bi_copy(x, t);
84572 }
84573
84574 /* x <- x * y, use t as temp */
84575 DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) {
84576         duk__bi_mul_small(t, x, y);
84577         duk__bi_copy(x, t);
84578 }
84579
84580 DUK_LOCAL int duk__bi_is_even(duk__bigint *x) {
84581         DUK_ASSERT(duk__bi_is_valid(x));
84582         return (x->n == 0) || ((x->v[0] & 0x01) == 0);
84583 }
84584
84585 DUK_LOCAL int duk__bi_is_zero(duk__bigint *x) {
84586         DUK_ASSERT(duk__bi_is_valid(x));
84587         return (x->n == 0);  /* this is the case for normalized numbers */
84588 }
84589
84590 /* Bigint is 2^52.  Used to detect normalized IEEE double mantissa values
84591  * which are at the lowest edge (next floating point value downwards has
84592  * a different exponent).  The lowest mantissa has the form:
84593  *
84594  *     1000........000    (52 zeroes; only "hidden bit" is set)
84595  */
84596 DUK_LOCAL duk_small_int_t duk__bi_is_2to52(duk__bigint *x) {
84597         DUK_ASSERT(duk__bi_is_valid(x));
84598         return (duk_small_int_t)
84599                 (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32)));
84600 }
84601
84602 /* x <- (1<<y) */
84603 DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
84604         duk_small_int_t n, r;
84605
84606         n = (y / 32) + 1;
84607         DUK_ASSERT(n > 0);
84608         r = y % 32;
84609         duk_memzero((void *) x->v, sizeof(duk_uint32_t) * (size_t) n);
84610         x->n = n;
84611         x->v[n - 1] = (((duk_uint32_t) 1) << r);
84612 }
84613
84614 /* x <- b^y; use t1 and t2 as temps */
84615 DUK_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) {
84616         /* Fast path the binary case */
84617
84618         DUK_ASSERT(x != t1 && x != t2 && t1 != t2);  /* distinct bignums, easy mistake to make */
84619         DUK_ASSERT(b >= 0);
84620         DUK_ASSERT(y >= 0);
84621
84622         if (b == 2) {
84623                 duk__bi_twoexp(x, y);
84624                 return;
84625         }
84626
84627         /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */
84628
84629         DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y));
84630
84631         duk__bi_set_small(x, 1);
84632         duk__bi_set_small(t1, (duk_uint32_t) b);
84633         for (;;) {
84634                 /* Loop structure ensures that we don't compute t1^2 unnecessarily
84635                  * on the final round, as that might create a bignum exceeding the
84636                  * current DUK__BI_MAX_PARTS limit.
84637                  */
84638                 if (y & 0x01) {
84639                         duk__bi_mul_copy(x, t1, t2);
84640                 }
84641                 y = y >> 1;
84642                 if (y == 0) {
84643                         break;
84644                 }
84645                 duk__bi_mul_copy(t1, t1, t2);
84646         }
84647
84648         DUK__BI_PRINT("exp_small result", x);
84649 }
84650
84651 /*
84652  *  A Dragon4 number-to-string variant, based on:
84653  *
84654  *    Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers
84655  *    Accurately"
84656  *
84657  *    Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers
84658  *    Quickly and Accurately"
84659  *
84660  *  The current algorithm is based on Figure 1 of the Burger-Dybvig paper,
84661  *  i.e. the base implementation without logarithm estimation speedups
84662  *  (these would increase code footprint considerably).  Fixed-format output
84663  *  does not follow the suggestions in the paper; instead, we generate an
84664  *  extra digit and round-with-carry.
84665  *
84666  *  The same algorithm is used for number parsing (with b=10 and B=2)
84667  *  by generating one extra digit and doing rounding manually.
84668  *
84669  *  See doc/number-conversion.rst for limitations.
84670  */
84671
84672 /* Maximum number of digits generated. */
84673 #define DUK__MAX_OUTPUT_DIGITS          1040  /* (Number.MAX_VALUE).toString(2).length == 1024, + slack */
84674
84675 /* Maximum number of characters in formatted value. */
84676 #define DUK__MAX_FORMATTED_LENGTH       1040  /* (-Number.MAX_VALUE).toString(2).length == 1025, + slack */
84677
84678 /* Number and (minimum) size of bigints in the nc_ctx structure. */
84679 #define DUK__NUMCONV_CTX_NUM_BIGINTS    7
84680 #define DUK__NUMCONV_CTX_BIGINTS_SIZE   (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS)
84681
84682 typedef struct {
84683         /* Currently about 7*152 = 1064 bytes.  The space for these
84684          * duk__bigints is used also as a temporary buffer for generating
84685          * the final string.  This is a bit awkard; a union would be
84686          * more correct.
84687          */
84688         duk__bigint f, r, s, mp, mm, t1, t2;
84689
84690         duk_small_int_t is_s2n;        /* if 1, doing a string-to-number; else doing a number-to-string */
84691         duk_small_int_t is_fixed;      /* if 1, doing a fixed format output (not free format) */
84692         duk_small_int_t req_digits;    /* requested number of output digits; 0 = free-format */
84693         duk_small_int_t abs_pos;       /* digit position is absolute, not relative */
84694         duk_small_int_t e;             /* exponent for 'f' */
84695         duk_small_int_t b;             /* input radix */
84696         duk_small_int_t B;             /* output radix */
84697         duk_small_int_t k;             /* see algorithm */
84698         duk_small_int_t low_ok;        /* see algorithm */
84699         duk_small_int_t high_ok;       /* see algorithm */
84700         duk_small_int_t unequal_gaps;  /* m+ != m- (very rarely) */
84701
84702         /* Buffer used for generated digits, values are in the range [0,B-1]. */
84703         duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS];
84704         duk_small_int_t count;  /* digit count */
84705 } duk__numconv_stringify_ctx;
84706
84707 /* Note: computes with 'idx' in assertions, so caller beware.
84708  * 'idx' is preincremented, i.e. '1' on first call, because it
84709  * is more convenient for the caller.
84710  */
84711 #define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x)  do { \
84712                 DUK_ASSERT((preinc_idx) - 1 >= 0); \
84713                 DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \
84714                 ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \
84715         } while (0)
84716
84717 DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) {
84718         duk_uint8_t *p;
84719         duk_size_t len;
84720         duk_small_int_t dig;
84721         duk_uint32_t t;
84722
84723         DUK_ASSERT(buf != NULL);
84724         DUK_ASSERT(radix >= 2 && radix <= 36);
84725
84726         /* A 32-bit unsigned integer formats to at most 32 digits (the
84727          * worst case happens with radix == 2).  Output the digits backwards,
84728          * and use a memmove() to get them in the right place.
84729          */
84730
84731         p = buf + 32;
84732         for (;;) {
84733                 t = x / (duk_uint32_t) radix;
84734                 dig = (duk_small_int_t) (x - t * (duk_uint32_t) radix);
84735                 x = t;
84736
84737                 DUK_ASSERT(dig >= 0 && dig < 36);
84738                 *(--p) = DUK__DIGITCHAR(dig);
84739
84740                 if (x == 0) {
84741                         break;
84742                 }
84743         }
84744         len = (duk_size_t) ((buf + 32) - p);
84745
84746         duk_memmove((void *) buf, (const void *) p, (size_t) len);
84747
84748         return len;
84749 }
84750
84751 DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
84752         duk_small_int_t lowest_mantissa;
84753
84754 #if 1
84755         /* Assume IEEE round-to-even, so that shorter encoding can be used
84756          * when round-to-even would produce correct result.  By removing
84757          * this check (and having low_ok == high_ok == 0) the results would
84758          * still be accurate but in some cases longer than necessary.
84759          */
84760         if (duk__bi_is_even(&nc_ctx->f)) {
84761                 DUK_DDD(DUK_DDDPRINT("f is even"));
84762                 nc_ctx->low_ok = 1;
84763                 nc_ctx->high_ok = 1;
84764         } else {
84765                 DUK_DDD(DUK_DDDPRINT("f is odd"));
84766                 nc_ctx->low_ok = 0;
84767                 nc_ctx->high_ok = 0;
84768         }
84769 #else
84770         /* Note: not honoring round-to-even should work but now generates incorrect
84771          * results.  For instance, 1e23 serializes to "a000...", i.e. the first digit
84772          * equals the radix (10).  Scaling stops one step too early in this case.
84773          * Don't know why this is the case, but since this code path is unused, it
84774          * doesn't matter.
84775          */
84776         nc_ctx->low_ok = 0;
84777         nc_ctx->high_ok = 0;
84778 #endif
84779
84780         /* For string-to-number, pretend we never have the lowest mantissa as there
84781          * is no natural "precision" for inputs.  Having lowest_mantissa == 0, we'll
84782          * fall into the base cases for both e >= 0 and e < 0.
84783          */
84784         if (nc_ctx->is_s2n) {
84785                 lowest_mantissa = 0;
84786         } else {
84787                 lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f);
84788         }
84789
84790         nc_ctx->unequal_gaps = 0;
84791         if (nc_ctx->e >= 0) {
84792                 /* exponent non-negative (and thus not minimum exponent) */
84793
84794                 if (lowest_mantissa) {
84795                         /* (>= e 0) AND (= f (expt b (- p 1)))
84796                          *
84797                          * be <- (expt b e) == b^e
84798                          * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1)
84799                          * r <- (* f be1 2) == 2 * f * b^(e+1)    [if b==2 -> f * b^(e+2)]
84800                          * s <- (* b 2)                           [if b==2 -> 4]
84801                          * m+ <- be1 == b^(e+1)
84802                          * m- <- be == b^e
84803                          * k <- 0
84804                          * B <- B
84805                          * low_ok <- round
84806                          * high_ok <- round
84807                          */
84808
84809                         DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
84810                                              "lowest mantissa value for this exponent -> "
84811                                              "unequal gaps"));
84812
84813                         duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2);  /* mm <- b^e */
84814                         duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, (duk_uint32_t) nc_ctx->b);           /* mp <- b^(e+1) */
84815                         duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
84816                         duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp);              /* r <- (2 * f) * b^(e+1) */
84817                         duk__bi_set_small(&nc_ctx->s, (duk_uint32_t) (nc_ctx->b * 2));  /* s <- 2 * b */
84818                         nc_ctx->unequal_gaps = 1;
84819                 } else {
84820                         /* (>= e 0) AND (not (= f (expt b (- p 1))))
84821                          *
84822                          * be <- (expt b e) == b^e
84823                          * r <- (* f be 2) == 2 * f * b^e    [if b==2 -> f * b^(e+1)]
84824                          * s <- 2
84825                          * m+ <- be == b^e
84826                          * m- <- be == b^e
84827                          * k <- 0
84828                          * B <- B
84829                          * low_ok <- round
84830                          * high_ok <- round
84831                          */
84832
84833                         DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
84834                                              "not lowest mantissa for this exponent -> "
84835                                              "equal gaps"));
84836
84837                         duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2);  /* mm <- b^e */
84838                         duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm);                /* mp <- b^e */
84839                         duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
84840                         duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp);     /* r <- (2 * f) * b^e */
84841                         duk__bi_set_small(&nc_ctx->s, 2);                      /* s <- 2 */
84842                 }
84843         } else {
84844                 /* When doing string-to-number, lowest_mantissa is always 0 so
84845                  * the exponent check, while incorrect, won't matter.
84846                  */
84847                 if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ &&
84848                     lowest_mantissa /* lowest mantissa for this exponent*/) {
84849                         /* r <- (* f b 2)                                [if b==2 -> (* f 4)]
84850                          * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2    [if b==2 -> b^(2-e)]
84851                          * m+ <- b == 2
84852                          * m- <- 1
84853                          * k <- 0
84854                          * B <- B
84855                          * low_ok <- round
84856                          * high_ok <- round
84857                          */
84858
84859                         DUK_DDD(DUK_DDDPRINT("negative exponent; not minimum exponent and "
84860                                              "lowest mantissa for this exponent -> "
84861                                              "unequal gaps"));
84862
84863                         duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, (duk_uint32_t) (nc_ctx->b * 2));  /* r <- (2 * b) * f */
84864                         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 */
84865                         duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2);             /* s <- b^(1-e) * 2 */
84866                         duk__bi_set_small(&nc_ctx->mp, 2);
84867                         duk__bi_set_small(&nc_ctx->mm, 1);
84868                         nc_ctx->unequal_gaps = 1;
84869                 } else {
84870                         /* r <- (* f 2)
84871                          * s <- (* (expt b (- e)) 2) == b^(-e) * 2    [if b==2 -> b^(1-e)]
84872                          * m+ <- 1
84873                          * m- <- 1
84874                          * k <- 0
84875                          * B <- B
84876                          * low_ok <- round
84877                          * high_ok <- round
84878                          */
84879
84880                         DUK_DDD(DUK_DDDPRINT("negative exponent; minimum exponent or not "
84881                                              "lowest mantissa for this exponent -> "
84882                                              "equal gaps"));
84883
84884                         duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2);            /* r <- 2 * f */
84885                         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 */
84886                         duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2);           /* s <- b^(-e) * 2 */
84887                         duk__bi_set_small(&nc_ctx->mp, 1);
84888                         duk__bi_set_small(&nc_ctx->mm, 1);
84889                 }
84890         }
84891 }
84892
84893 DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
84894         duk_small_int_t k = 0;
84895
84896         /* This is essentially the 'scale' algorithm, with recursion removed.
84897          * Note that 'k' is either correct immediately, or will move in one
84898          * direction in the loop.  There's no need to do the low/high checks
84899          * on every round (like the Scheme algorithm does).
84900          *
84901          * The scheme algorithm finds 'k' and updates 's' simultaneously,
84902          * while the logical algorithm finds 'k' with 's' having its initial
84903          * value, after which 's' is updated separately (see the Burger-Dybvig
84904          * paper, Section 3.1, steps 2 and 3).
84905          *
84906          * The case where m+ == m- (almost always) is optimized for, because
84907          * it reduces the bigint operations considerably and almost always
84908          * applies.  The scale loop only needs to work with m+, so this works.
84909          */
84910
84911         /* XXX: this algorithm could be optimized quite a lot by using e.g.
84912          * a logarithm based estimator for 'k' and performing B^n multiplication
84913          * using a lookup table or using some bit-representation based exp
84914          * algorithm.  Currently we just loop, with significant performance
84915          * impact for very large and very small numbers.
84916          */
84917
84918         DUK_DDD(DUK_DDDPRINT("scale: B=%ld, low_ok=%ld, high_ok=%ld",
84919                              (long) nc_ctx->B, (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
84920         DUK__BI_PRINT("r(init)", &nc_ctx->r);
84921         DUK__BI_PRINT("s(init)", &nc_ctx->s);
84922         DUK__BI_PRINT("mp(init)", &nc_ctx->mp);
84923         DUK__BI_PRINT("mm(init)", &nc_ctx->mm);
84924
84925         for (;;) {
84926                 DUK_DDD(DUK_DDDPRINT("scale loop (inc k), k=%ld", (long) k));
84927                 DUK__BI_PRINT("r", &nc_ctx->r);
84928                 DUK__BI_PRINT("s", &nc_ctx->s);
84929                 DUK__BI_PRINT("m+", &nc_ctx->mp);
84930                 DUK__BI_PRINT("m-", &nc_ctx->mm);
84931
84932                 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp);  /* t1 = (+ r m+) */
84933                 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) {
84934                         DUK_DDD(DUK_DDDPRINT("k is too low"));
84935                         /* r <- r
84936                          * s <- (* s B)
84937                          * m+ <- m+
84938                          * m- <- m-
84939                          * k <- (+ k 1)
84940                          */
84941
84942                         duk__bi_mul_small_copy(&nc_ctx->s, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
84943                         k++;
84944                 } else {
84945                         break;
84946                 }
84947         }
84948
84949         /* k > 0 -> k was too low, and cannot be too high */
84950         if (k > 0) {
84951                 goto skip_dec_k;
84952         }
84953
84954         for (;;) {
84955                 DUK_DDD(DUK_DDDPRINT("scale loop (dec k), k=%ld", (long) k));
84956                 DUK__BI_PRINT("r", &nc_ctx->r);
84957                 DUK__BI_PRINT("s", &nc_ctx->s);
84958                 DUK__BI_PRINT("m+", &nc_ctx->mp);
84959                 DUK__BI_PRINT("m-", &nc_ctx->mm);
84960
84961                 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp);  /* t1 = (+ r m+) */
84962                 duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, (duk_uint32_t) nc_ctx->B);   /* t2 = (* (+ r m+) B) */
84963                 if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
84964                         DUK_DDD(DUK_DDDPRINT("k is too high"));
84965                         /* r <- (* r B)
84966                          * s <- s
84967                          * m+ <- (* m+ B)
84968                          * m- <- (* m- B)
84969                          * k <- (- k 1)
84970                          */
84971                         duk__bi_mul_small_copy(&nc_ctx->r, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
84972                         duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
84973                         if (nc_ctx->unequal_gaps) {
84974                                 DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too"));
84975                                 duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t1);
84976                         }
84977                         k--;
84978                 } else {
84979                         break;
84980                 }
84981         }
84982
84983  skip_dec_k:
84984
84985         if (!nc_ctx->unequal_gaps) {
84986                 DUK_DDD(DUK_DDDPRINT("equal gaps, copy m- from m+"));
84987                 duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp);  /* mm <- mp */
84988         }
84989         nc_ctx->k = k;
84990
84991         DUK_DDD(DUK_DDDPRINT("final k: %ld", (long) k));
84992         DUK__BI_PRINT("r(final)", &nc_ctx->r);
84993         DUK__BI_PRINT("s(final)", &nc_ctx->s);
84994         DUK__BI_PRINT("mp(final)", &nc_ctx->mp);
84995         DUK__BI_PRINT("mm(final)", &nc_ctx->mm);
84996 }
84997
84998 DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
84999         duk_small_int_t tc1, tc2;    /* terminating conditions */
85000         duk_small_int_t d;           /* current digit */
85001         duk_small_int_t count = 0;   /* digit count */
85002
85003         /*
85004          *  Digit generation loop.
85005          *
85006          *  Different termination conditions:
85007          *
85008          *    1. Free format output.  Terminate when shortest accurate
85009          *       representation found.
85010          *
85011          *    2. Fixed format output, with specific number of digits.
85012          *       Ignore termination conditions, terminate when digits
85013          *       generated.  Caller requests an extra digit and rounds.
85014          *
85015          *    3. Fixed format output, with a specific absolute cut-off
85016          *       position (e.g. 10 digits after decimal point).  Note
85017          *       that we always generate at least one digit, even if
85018          *       the digit is below the cut-off point already.
85019          */
85020
85021         for (;;) {
85022                 DUK_DDD(DUK_DDDPRINT("generate loop, count=%ld, k=%ld, B=%ld, low_ok=%ld, high_ok=%ld",
85023                                      (long) count, (long) nc_ctx->k, (long) nc_ctx->B,
85024                                      (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
85025                 DUK__BI_PRINT("r", &nc_ctx->r);
85026                 DUK__BI_PRINT("s", &nc_ctx->s);
85027                 DUK__BI_PRINT("m+", &nc_ctx->mp);
85028                 DUK__BI_PRINT("m-", &nc_ctx->mm);
85029
85030                 /* (quotient-remainder (* r B) s) using a dummy subtraction loop */
85031                 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, (duk_uint32_t) nc_ctx->B);       /* t1 <- (* r B) */
85032                 d = 0;
85033                 for (;;) {
85034                         if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
85035                                 break;
85036                         }
85037                         duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2);  /* t1 <- t1 - s */
85038                         d++;
85039                 }
85040                 duk__bi_copy(&nc_ctx->r, &nc_ctx->t1);  /* r <- (remainder (* r B) s) */
85041                                                         /* d <- (quotient (* r B) s)   (in range 0...B-1) */
85042                 DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d));
85043                 DUK__BI_PRINT("r(rem)", &nc_ctx->r);
85044
85045                 duk__bi_mul_small_copy(&nc_ctx->mp, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
85046                 duk__bi_mul_small_copy(&nc_ctx->mm, (duk_uint32_t) nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
85047                 DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
85048                 DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
85049
85050                 /* Terminating conditions.  For fixed width output, we just ignore the
85051                  * terminating conditions (and pretend that tc1 == tc2 == false).  The
85052                  * the current shortcut for fixed-format output is to generate a few
85053                  * extra digits and use rounding (with carry) to finish the output.
85054                  */
85055
85056                 if (nc_ctx->is_fixed == 0) {
85057                         /* free-form */
85058                         tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1));
85059
85060                         duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp);  /* t1 <- (+ r m+) */
85061                         tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1));
85062
85063                         DUK_DDD(DUK_DDDPRINT("tc1=%ld, tc2=%ld", (long) tc1, (long) tc2));
85064                 } else {
85065                         /* fixed-format */
85066                         tc1 = 0;
85067                         tc2 = 0;
85068                 }
85069
85070                 /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call
85071                  * on purpose, which is taken into account by the macro.
85072                  */
85073                 count++;
85074
85075                 if (tc1) {
85076                         if (tc2) {
85077                                 /* tc1 = true, tc2 = true */
85078                                 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2);
85079                                 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {  /* (< (* r 2) s) */
85080                                         DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %ld (k=%ld)",
85081                                                              (long) d, (long) nc_ctx->k));
85082                                         DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
85083                                 } else {
85084                                         DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %ld (k=%ld)",
85085                                                              (long) (d + 1), (long) nc_ctx->k));
85086                                         DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
85087                                 }
85088                                 break;
85089                         } else {
85090                                 /* tc1 = true, tc2 = false */
85091                                 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=false: output d --> %ld (k=%ld)",
85092                                                      (long) d, (long) nc_ctx->k));
85093                                 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
85094                                 break;
85095                         }
85096                 } else {
85097                         if (tc2) {
85098                                 /* tc1 = false, tc2 = true */
85099                                 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %ld (k=%ld)",
85100                                                      (long) (d + 1), (long) nc_ctx->k));
85101                                 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
85102                                 break;
85103                         } else {
85104                                 /* tc1 = false, tc2 = false */
85105                                 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=false: output d --> %ld (k=%ld)",
85106                                                      (long) d, (long) nc_ctx->k));
85107                                 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
85108
85109                                 /* r <- r    (updated above: r <- (remainder (* r B) s)
85110                                  * s <- s
85111                                  * m+ <- m+  (updated above: m+ <- (* m+ B)
85112                                  * m- <- m-  (updated above: m- <- (* m- B)
85113                                  * B, low_ok, high_ok are fixed
85114                                  */
85115
85116                                 /* fall through and continue for-loop */
85117                         }
85118                 }
85119
85120                 /* fixed-format termination conditions */
85121                 if (nc_ctx->is_fixed) {
85122                         if (nc_ctx->abs_pos) {
85123                                 int pos = nc_ctx->k - count + 1;  /* count is already incremented, take into account */
85124                                 DUK_DDD(DUK_DDDPRINT("fixed format, absolute: abs pos=%ld, k=%ld, count=%ld, req=%ld",
85125                                                      (long) pos, (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
85126                                 if (pos <= nc_ctx->req_digits) {
85127                                         DUK_DDD(DUK_DDDPRINT("digit position reached req_digits, end generate loop"));
85128                                         break;
85129                                 }
85130                         } else {
85131                                 DUK_DDD(DUK_DDDPRINT("fixed format, relative: k=%ld, count=%ld, req=%ld",
85132                                                      (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
85133                                 if (count >= nc_ctx->req_digits) {
85134                                         DUK_DDD(DUK_DDDPRINT("digit count reached req_digits, end generate loop"));
85135                                         break;
85136                                 }
85137                         }
85138                 }
85139         }  /* for */
85140
85141         nc_ctx->count = count;
85142
85143         DUK_DDD(DUK_DDDPRINT("generate finished"));
85144
85145 #if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
85146         {
85147                 duk_uint8_t buf[2048];
85148                 duk_small_int_t i, t;
85149                 duk_memzero(buf, sizeof(buf));
85150                 for (i = 0; i < nc_ctx->count; i++) {
85151                         t = nc_ctx->digits[i];
85152                         if (t < 0 || t > 36) {
85153                                 buf[i] = (duk_uint8_t) '?';
85154                         } else {
85155                                 buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t);
85156                         }
85157                 }
85158                 DUK_DDD(DUK_DDDPRINT("-> generated digits; k=%ld, digits='%s'",
85159                                      (long) nc_ctx->k, (const char *) buf));
85160         }
85161 #endif
85162 }
85163
85164 /* Round up digits to a given position.  If position is out-of-bounds,
85165  * does nothing.  If carry propagates over the first digit, a '1' is
85166  * prepended to digits and 'k' will be updated.  Return value indicates
85167  * whether carry propagated over the first digit.
85168  *
85169  * Note that nc_ctx->count is NOT updated based on the rounding position
85170  * (it is updated only if carry overflows over the first digit and an
85171  * extra digit is prepended).
85172  */
85173 DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) {
85174         duk_small_int_t t;
85175         duk_uint8_t *p;
85176         duk_uint8_t roundup_limit;
85177         duk_small_int_t ret = 0;
85178
85179         /*
85180          *  round_idx points to the digit which is considered for rounding; the
85181          *  digit to its left is the final digit of the rounded value.  If round_idx
85182          *  is zero, rounding will be performed; the result will either be an empty
85183          *  rounded value or if carry happens a '1' digit is generated.
85184          */
85185
85186         if (round_idx >= nc_ctx->count) {
85187                 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld >= %ld (count)) -> no rounding",
85188                                      (long) round_idx, (long) nc_ctx->count));
85189                 return 0;
85190         } else if (round_idx < 0) {
85191                 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld < 0) -> no rounding",
85192                                      (long) round_idx));
85193                 return 0;
85194         }
85195
85196         /*
85197          *  Round-up limit.
85198          *
85199          *  For even values, divides evenly, e.g. 10 -> roundup_limit=5.
85200          *
85201          *  For odd values, rounds up, e.g. 3 -> roundup_limit=2.
85202          *  If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up.
85203          */
85204         roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2);
85205
85206         p = &nc_ctx->digits[round_idx];
85207         if (*p >= roundup_limit) {
85208                 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry required"));
85209                 /* carry */
85210                 for (;;) {
85211                         *p = 0;
85212                         if (p == &nc_ctx->digits[0]) {
85213                                 DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
85214                                 duk_memmove((void *) (&nc_ctx->digits[1]),
85215                                             (const void *) (&nc_ctx->digits[0]),
85216                                             (size_t) (sizeof(char) * (size_t) nc_ctx->count));
85217                                 nc_ctx->digits[0] = 1;  /* don't increase 'count' */
85218                                 nc_ctx->k++;  /* position of highest digit changed */
85219                                 nc_ctx->count++;  /* number of digits changed */
85220                                 ret = 1;
85221                                 break;
85222                         }
85223
85224                         DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry: B=%ld, roundup_limit=%ld, p=%p, digits=%p",
85225                                              (long) nc_ctx->B, (long) roundup_limit, (void *) p, (void *) nc_ctx->digits));
85226                         p--;
85227                         t = *p;
85228                         DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
85229                         if (++t < nc_ctx->B) {
85230                                 DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
85231                                 *p = (duk_uint8_t) t;
85232                                 break;
85233                         }
85234
85235                         DUK_DDD(DUK_DDDPRINT("wraps, carry to next digit"));
85236                 }
85237         }
85238
85239         return ret;
85240 }
85241
85242 #define DUK__NO_EXP  (65536)  /* arbitrary marker, outside valid exp range */
85243
85244 DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
85245                                              duk_hthread *thr,
85246                                              duk_small_int_t radix,
85247                                              duk_small_int_t digits,
85248                                              duk_small_uint_t flags,
85249                                              duk_small_int_t neg) {
85250         duk_small_int_t k;
85251         duk_small_int_t pos, pos_end;
85252         duk_small_int_t expt;
85253         duk_small_int_t dig;
85254         duk_uint8_t *q;
85255         duk_uint8_t *buf;
85256
85257         /*
85258          *  The string conversion here incorporates all the necessary ECMAScript
85259          *  semantics without attempting to be generic.  nc_ctx->digits contains
85260          *  nc_ctx->count digits (>= 1), with the topmost digit's 'position'
85261          *  indicated by nc_ctx->k as follows:
85262          *
85263          *    digits="123" count=3 k=0   -->   0.123
85264          *    digits="123" count=3 k=1   -->   1.23
85265          *    digits="123" count=3 k=5   -->   12300
85266          *    digits="123" count=3 k=-1  -->   0.0123
85267          *
85268          *  Note that the identifier names used for format selection are different
85269          *  in Burger-Dybvig paper and ECMAScript specification (quite confusingly
85270          *  so, because e.g. 'k' has a totally different meaning in each).  See
85271          *  documentation for discussion.
85272          *
85273          *  ECMAScript doesn't specify any specific behavior for format selection
85274          *  (e.g. when to use exponent notation) for non-base-10 numbers.
85275          *
85276          *  The bigint space in the context is reused for string output, as there
85277          *  is more than enough space for that (>1kB at the moment), and we avoid
85278          *  allocating even more stack.
85279          */
85280
85281         DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH);
85282         DUK_ASSERT(nc_ctx->count >= 1);
85283
85284         k = nc_ctx->k;
85285         buf = (duk_uint8_t *) &nc_ctx->f;  /* XXX: union would be more correct */
85286         q = buf;
85287
85288         /* Exponent handling: if exponent format is used, record exponent value and
85289          * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23").
85290          *
85291          * toFixed() prevents exponent use; otherwise apply a set of criteria to
85292          * match the other API calls (toString(), toPrecision, etc).
85293          */
85294
85295         expt = DUK__NO_EXP;
85296         if (!nc_ctx->abs_pos /* toFixed() */) {
85297                 if ((flags & DUK_N2S_FLAG_FORCE_EXP) ||             /* exponential notation forced */
85298                     ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) &&          /* fixed precision and zero padding would be required */
85299                      (k - digits >= 1)) ||                          /* (e.g. k=3, digits=2 -> "12X") */
85300                     ((k > 21 || k <= -6) && (radix == 10))) {       /* toString() conditions */
85301                         DUK_DDD(DUK_DDDPRINT("use exponential notation: k=%ld -> expt=%ld",
85302                                              (long) k, (long) (k - 1)));
85303                         expt = k - 1;  /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */
85304                         k = 1;  /* generate mantissa with a single leading whole number digit */
85305                 }
85306         }
85307
85308         if (neg) {
85309                 *q++ = '-';
85310         }
85311
85312         /* Start position (inclusive) and end position (exclusive) */
85313         pos = (k >= 1 ? k : 1);
85314         if (nc_ctx->is_fixed) {
85315                 if (nc_ctx->abs_pos) {
85316                         /* toFixed() */
85317                         pos_end = -digits;
85318                 } else {
85319                         pos_end = k - digits;
85320                 }
85321         } else {
85322                 pos_end = k - nc_ctx->count;
85323         }
85324         if (pos_end > 0) {
85325                 pos_end = 0;
85326         }
85327
85328         DUK_DDD(DUK_DDDPRINT("expt=%ld, k=%ld, count=%ld, pos=%ld, pos_end=%ld, is_fixed=%ld, "
85329                              "digits=%ld, abs_pos=%ld",
85330                              (long) expt, (long) k, (long) nc_ctx->count, (long) pos, (long) pos_end,
85331                              (long) nc_ctx->is_fixed, (long) digits, (long) nc_ctx->abs_pos));
85332
85333         /* Digit generation */
85334         while (pos > pos_end) {
85335                 DUK_DDD(DUK_DDDPRINT("digit generation: pos=%ld, pos_end=%ld",
85336                                      (long) pos, (long) pos_end));
85337                 if (pos == 0) {
85338                         *q++ = (duk_uint8_t) '.';
85339                 }
85340                 if (pos > k) {
85341                         *q++ = (duk_uint8_t) '0';
85342                 } else if (pos <= k - nc_ctx->count) {
85343                         *q++ = (duk_uint8_t) '0';
85344                 } else {
85345                         dig = nc_ctx->digits[k - pos];
85346                         DUK_ASSERT(dig >= 0 && dig < nc_ctx->B);
85347                         *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig);
85348                 }
85349
85350                 pos--;
85351         }
85352         DUK_ASSERT(pos <= 1);
85353
85354         /* Exponent */
85355         if (expt != DUK__NO_EXP) {
85356                 /*
85357                  *  Exponent notation for non-base-10 numbers isn't specified in ECMAScript
85358                  *  specification, as it never explicitly turns up: non-decimal numbers can
85359                  *  only be formatted with Number.prototype.toString([radix]) and for that,
85360                  *  behavior is not explicitly specified.
85361                  *
85362                  *  Logical choices include formatting the exponent as decimal (e.g. binary
85363                  *  100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101).
85364                  *  The Dragon4 algorithm (in the original paper) prints the exponent value
85365                  *  in the target radix B.  However, for radix values 15 and above, the
85366                  *  exponent separator 'e' is no longer easily parseable.  Consider, for
85367                  *  instance, the number "1.faecee+1c".
85368                  */
85369
85370                 duk_size_t len;
85371                 char expt_sign;
85372
85373                 *q++ = 'e';
85374                 if (expt >= 0) {
85375                         expt_sign = '+';
85376                 } else {
85377                         expt_sign = '-';
85378                         expt = -expt;
85379                 }
85380                 *q++ = (duk_uint8_t) expt_sign;
85381                 len = duk__dragon4_format_uint32(q, (duk_uint32_t) expt, radix);
85382                 q += len;
85383         }
85384
85385         duk_push_lstring(thr, (const char *) buf, (size_t) (q - buf));
85386 }
85387
85388 /*
85389  *  Conversion helpers
85390  */
85391
85392 DUK_LOCAL void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) {
85393         duk_double_union u;
85394         duk_uint32_t tmp;
85395         duk_small_int_t expt;
85396
85397         /*
85398          *    seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
85399          *       A        B        C        D        E        F        G        H
85400          *
85401          *    s       sign bit
85402          *    eee...  exponent field
85403          *    fff...  fraction
85404          *
85405          *    ieee value = 1.ffff... * 2^(e - 1023)  (normal)
85406          *               = 0.ffff... * 2^(-1022)     (denormal)
85407          *
85408          *    algorithm v = f * b^e
85409          */
85410
85411         DUK_DBLUNION_SET_DOUBLE(&u, x);
85412
85413         nc_ctx->f.n = 2;
85414
85415         tmp = DUK_DBLUNION_GET_LOW32(&u);
85416         nc_ctx->f.v[0] = tmp;
85417         tmp = DUK_DBLUNION_GET_HIGH32(&u);
85418         nc_ctx->f.v[1] = tmp & 0x000fffffUL;
85419         expt = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL);
85420
85421         if (expt == 0) {
85422                 /* denormal */
85423                 expt = DUK__IEEE_DOUBLE_EXP_MIN - 52;
85424                 duk__bi_normalize(&nc_ctx->f);
85425         } else {
85426                 /* normal: implicit leading 1-bit */
85427                 nc_ctx->f.v[1] |= 0x00100000UL;
85428                 expt = expt - DUK__IEEE_DOUBLE_EXP_BIAS - 52;
85429                 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));  /* true, because v[1] has at least one bit set */
85430         }
85431
85432         DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));
85433
85434         nc_ctx->e = expt;
85435 }
85436
85437 DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) {
85438         duk_double_union u;
85439         duk_small_int_t expt;
85440         duk_small_int_t i;
85441         duk_small_int_t bitstart;
85442         duk_small_int_t bitround;
85443         duk_small_int_t bitidx;
85444         duk_small_int_t skip_round;
85445         duk_uint32_t t, v;
85446
85447         DUK_ASSERT(nc_ctx->count == 53 + 1);
85448
85449         /* Sometimes this assert is not true right now; it will be true after
85450          * rounding.  See: test-bug-numconv-mantissa-assert.js.
85451          */
85452         DUK_ASSERT_DISABLE(nc_ctx->digits[0] == 1);  /* zero handled by caller */
85453
85454         /* Should not be required because the code below always sets both high
85455          * and low parts, but at least gcc-4.4.5 fails to deduce this correctly
85456          * (perhaps because the low part is set (seemingly) conditionally in a
85457          * loop), so this is here to avoid the bogus warning.
85458          */
85459         duk_memzero((void *) &u, sizeof(u));
85460
85461         /*
85462          *  Figure out how generated digits match up with the mantissa,
85463          *  and then perform rounding.  If mantissa overflows, need to
85464          *  recompute the exponent (it is bumped and may overflow to
85465          *  infinity).
85466          *
85467          *  For normal numbers the leading '1' is hidden and ignored,
85468          *  and the last bit is used for rounding:
85469          *
85470          *                          rounding pt
85471          *       <--------52------->|
85472          *     1 x x x x ... x x x x|y  ==>  x x x x ... x x x x
85473          *
85474          *  For denormals, the leading '1' is included in the number,
85475          *  and the rounding point is different:
85476          *
85477          *                      rounding pt
85478          *     <--52 or less--->|
85479          *     1 x x x x ... x x|x x y  ==>  0 0 ... 1 x x ... x x
85480          *
85481          *  The largest denormals will have a mantissa beginning with
85482          *  a '1' (the explicit leading bit); smaller denormals will
85483          *  have leading zero bits.
85484          *
85485          *  If the exponent would become too high, the result becomes
85486          *  Infinity.  If the exponent is so small that the entire
85487          *  mantissa becomes zero, the result becomes zero.
85488          *
85489          *  Note: the Dragon4 'k' is off-by-one with respect to the IEEE
85490          *  exponent.  For instance, k==0 indicates that the leading '1'
85491          *  digit is at the first binary fraction position (0.1xxx...);
85492          *  the corresponding IEEE exponent would be -1.
85493          */
85494
85495         skip_round = 0;
85496
85497  recheck_exp:
85498
85499         expt = nc_ctx->k - 1;   /* IEEE exp without bias */
85500         if (expt > 1023) {
85501                 /* Infinity */
85502                 bitstart = -255;  /* needed for inf: causes mantissa to become zero,
85503                                    * and rounding to be skipped.
85504                                    */
85505                 expt = 2047;
85506         } else if (expt >= -1022) {
85507                 /* normal */
85508                 bitstart = 1;  /* skip leading digit */
85509                 expt += DUK__IEEE_DOUBLE_EXP_BIAS;
85510                 DUK_ASSERT(expt >= 1 && expt <= 2046);
85511         } else {
85512                 /* denormal or zero */
85513                 bitstart = 1023 + expt;  /* expt==-1023 -> bitstart=0 (leading 1);
85514                                           * expt==-1024 -> bitstart=-1 (one left of leading 1), etc
85515                                           */
85516                 expt = 0;
85517         }
85518         bitround = bitstart + 52;
85519
85520         DUK_DDD(DUK_DDDPRINT("ieee expt=%ld, bitstart=%ld, bitround=%ld",
85521                              (long) expt, (long) bitstart, (long) bitround));
85522
85523         if (!skip_round) {
85524                 if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) {
85525                         /* Corner case: see test-numconv-parse-mant-carry.js.  We could
85526                          * just bump the exponent and update bitstart, but it's more robust
85527                          * to recompute (but avoid rounding twice).
85528                          */
85529                         DUK_DDD(DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent"));
85530                         skip_round = 1;
85531                         goto recheck_exp;
85532                 }
85533         }
85534
85535         /*
85536          *  Create mantissa
85537          */
85538
85539         t = 0;
85540         for (i = 0; i < 52; i++) {
85541                 bitidx = bitstart + 52 - 1 - i;
85542                 if (bitidx >= nc_ctx->count) {
85543                         v = 0;
85544                 } else if (bitidx < 0) {
85545                         v = 0;
85546                 } else {
85547                         v = nc_ctx->digits[bitidx];
85548                 }
85549                 DUK_ASSERT(v == 0 || v == 1);
85550                 t += v << (i % 32);
85551                 if (i == 31) {
85552                         /* low 32 bits is complete */
85553                         DUK_DBLUNION_SET_LOW32(&u, t);
85554                         t = 0;
85555                 }
85556         }
85557         /* t has high mantissa */
85558
85559         DUK_DDD(DUK_DDDPRINT("mantissa is complete: %08lx %08lx",
85560                              (unsigned long) t,
85561                              (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
85562
85563         DUK_ASSERT(expt >= 0 && expt <= 0x7ffL);
85564         t += ((duk_uint32_t) expt) << 20;
85565 #if 0  /* caller handles sign change */
85566         if (negative) {
85567                 t |= 0x80000000U;
85568         }
85569 #endif
85570         DUK_DBLUNION_SET_HIGH32(&u, t);
85571
85572         DUK_DDD(DUK_DDDPRINT("number is complete: %08lx %08lx",
85573                              (unsigned long) DUK_DBLUNION_GET_HIGH32(&u),
85574                              (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
85575
85576         *x = DUK_DBLUNION_GET_DOUBLE(&u);
85577 }
85578
85579 /*
85580  *  Exposed number-to-string API
85581  *
85582  *  Input: [ number ]
85583  *  Output: [ string ]
85584  */
85585
85586 DUK_INTERNAL void duk_numconv_stringify(duk_hthread *thr, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
85587         duk_double_t x;
85588         duk_small_int_t c;
85589         duk_small_int_t neg;
85590         duk_uint32_t uval;
85591         duk__numconv_stringify_ctx nc_ctx_alloc;  /* large context; around 2kB now */
85592         duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
85593
85594         x = (duk_double_t) duk_require_number(thr, -1);
85595         duk_pop(thr);
85596
85597         /*
85598          *  Handle special cases (NaN, infinity, zero).
85599          */
85600
85601         c = (duk_small_int_t) DUK_FPCLASSIFY(x);
85602         if (DUK_SIGNBIT((double) x)) {
85603                 x = -x;
85604                 neg = 1;
85605         } else {
85606                 neg = 0;
85607         }
85608
85609         /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */
85610         DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
85611
85612         if (c == DUK_FP_NAN) {
85613                 duk_push_hstring_stridx(thr, DUK_STRIDX_NAN);
85614                 return;
85615         } else if (c == DUK_FP_INFINITE) {
85616                 if (neg) {
85617                         /* -Infinity */
85618                         duk_push_hstring_stridx(thr, DUK_STRIDX_MINUS_INFINITY);
85619                 } else {
85620                         /* Infinity */
85621                         duk_push_hstring_stridx(thr, DUK_STRIDX_INFINITY);
85622                 }
85623                 return;
85624         } else if (c == DUK_FP_ZERO) {
85625                 /* We can't shortcut zero here if it goes through special formatting
85626                  * (such as forced exponential notation).
85627                  */
85628                 ;
85629         }
85630
85631         /*
85632          *  Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1])
85633          *  specially, as they're very likely for embedded programs.  This
85634          *  is now done for all radix values.  We must be careful not to use
85635          *  the fast path when special formatting (e.g. forced exponential)
85636          *  is in force.
85637          *
85638          *  XXX: could save space by supporting radix 10 only and using
85639          *  sprintf "%lu" for the fast path and for exponent formatting.
85640          */
85641
85642         uval = duk_double_to_uint32_t(x);
85643         if (((double) uval) == x &&  /* integer number in range */
85644             flags == 0) {            /* no special formatting */
85645                 /* use bigint area as a temp */
85646                 duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f);
85647                 duk_uint8_t *p = buf;
85648
85649                 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1);  /* max size: radix=2 + sign */
85650                 if (neg && uval != 0) {
85651                         /* no negative sign for zero */
85652                         *p++ = (duk_uint8_t) '-';
85653                 }
85654                 p += duk__dragon4_format_uint32(p, uval, radix);
85655                 duk_push_lstring(thr, (const char *) buf, (duk_size_t) (p - buf));
85656                 return;
85657         }
85658
85659         /*
85660          *  Dragon4 setup.
85661          *
85662          *  Convert double from IEEE representation for conversion;
85663          *  normal finite values have an implicit leading 1-bit.  The
85664          *  slow path algorithm doesn't handle zero, so zero is special
85665          *  cased here but still creates a valid nc_ctx, and goes
85666          *  through normal formatting in case special formatting has
85667          *  been requested (e.g. forced exponential format: 0 -> "0e+0").
85668          */
85669
85670         /* Would be nice to bulk clear the allocation, but the context
85671          * is 1-2 kilobytes and nothing should rely on it being zeroed.
85672          */
85673 #if 0
85674         duk_memzero((void *) nc_ctx, sizeof(*nc_ctx));  /* slow init, do only for slow path cases */
85675 #endif
85676
85677         nc_ctx->is_s2n = 0;
85678         nc_ctx->b = 2;
85679         nc_ctx->B = radix;
85680         nc_ctx->abs_pos = 0;
85681         if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
85682                 nc_ctx->is_fixed = 1;
85683                 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
85684                         /* absolute req_digits; e.g. digits = 1 -> last digit is 0,
85685                          * but add an extra digit for rounding.
85686                          */
85687                         nc_ctx->abs_pos = 1;
85688                         nc_ctx->req_digits = (-digits + 1) - 1;
85689                 } else {
85690                         nc_ctx->req_digits = digits + 1;
85691                 }
85692         } else {
85693                 nc_ctx->is_fixed = 0;
85694                 nc_ctx->req_digits = 0;
85695         }
85696
85697         if (c == DUK_FP_ZERO) {
85698                 /* Zero special case: fake requested number of zero digits; ensure
85699                  * no sign bit is printed.  Relative and absolute fixed format
85700                  * require separate handling.
85701                  */
85702                 duk_small_int_t count;
85703                 if (nc_ctx->is_fixed) {
85704                         if (nc_ctx->abs_pos) {
85705                                 count = digits + 2;  /* lead zero + 'digits' fractions + 1 for rounding */
85706                         } else {
85707                                 count = digits + 1;  /* + 1 for rounding */
85708                         }
85709                 } else {
85710                         count = 1;
85711                 }
85712                 DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
85713                 DUK_ASSERT(count >= 1);
85714                 duk_memzero((void *) nc_ctx->digits, (size_t) count);
85715                 nc_ctx->count = count;
85716                 nc_ctx->k = 1;  /* 0.000... */
85717                 neg = 0;
85718                 goto zero_skip;
85719         }
85720
85721         duk__dragon4_double_to_ctx(nc_ctx, x);   /* -> sets 'f' and 'e' */
85722         DUK__BI_PRINT("f", &nc_ctx->f);
85723         DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
85724
85725         /*
85726          *  Dragon4 slow path digit generation.
85727          */
85728
85729         duk__dragon4_prepare(nc_ctx);  /* setup many variables in nc_ctx */
85730
85731         DUK_DDD(DUK_DDDPRINT("after prepare:"));
85732         DUK__BI_PRINT("r", &nc_ctx->r);
85733         DUK__BI_PRINT("s", &nc_ctx->s);
85734         DUK__BI_PRINT("mp", &nc_ctx->mp);
85735         DUK__BI_PRINT("mm", &nc_ctx->mm);
85736
85737         duk__dragon4_scale(nc_ctx);
85738
85739         DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
85740         DUK__BI_PRINT("r", &nc_ctx->r);
85741         DUK__BI_PRINT("s", &nc_ctx->s);
85742         DUK__BI_PRINT("mp", &nc_ctx->mp);
85743         DUK__BI_PRINT("mm", &nc_ctx->mm);
85744
85745         duk__dragon4_generate(nc_ctx);
85746
85747         /*
85748          *  Convert and push final string.
85749          */
85750
85751  zero_skip:
85752
85753         if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
85754                 /* Perform fixed-format rounding. */
85755                 duk_small_int_t roundpos;
85756                 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
85757                         /* 'roundpos' is relative to nc_ctx->k and increases to the right
85758                          * (opposite of how 'k' changes).
85759                          */
85760                         roundpos = -digits;  /* absolute position for digit considered for rounding */
85761                         roundpos = nc_ctx->k - roundpos;
85762                 } else {
85763                         roundpos = digits;
85764                 }
85765                 DUK_DDD(DUK_DDDPRINT("rounding: k=%ld, count=%ld, digits=%ld, roundpos=%ld",
85766                                      (long) nc_ctx->k, (long) nc_ctx->count, (long) digits, (long) roundpos));
85767                 (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos);
85768
85769                 /* Note: 'count' is currently not adjusted by rounding (i.e. the
85770                  * digits are not "chopped off".  That shouldn't matter because
85771                  * the digit position (absolute or relative) is passed on to the
85772                  * convert-and-push function.
85773                  */
85774         }
85775
85776         duk__dragon4_convert_and_push(nc_ctx, thr, radix, digits, flags, neg);
85777 }
85778
85779 /*
85780  *  Exposed string-to-number API
85781  *
85782  *  Input: [ string ]
85783  *  Output: [ number ]
85784  *
85785  *  If number parsing fails, a NaN is pushed as the result.  If number parsing
85786  *  fails due to an internal error, an InternalError is thrown.
85787  */
85788
85789 DUK_INTERNAL void duk_numconv_parse(duk_hthread *thr, duk_small_int_t radix, duk_small_uint_t flags) {
85790         duk__numconv_stringify_ctx nc_ctx_alloc;  /* large context; around 2kB now */
85791         duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
85792         duk_double_t res;
85793         duk_hstring *h_str;
85794         duk_int_t expt;
85795         duk_bool_t expt_neg;
85796         duk_small_int_t expt_adj;
85797         duk_small_int_t neg;
85798         duk_small_int_t dig;
85799         duk_small_int_t dig_whole;
85800         duk_small_int_t dig_lzero;
85801         duk_small_int_t dig_frac;
85802         duk_small_int_t dig_expt;
85803         duk_small_int_t dig_prec;
85804         const duk__exp_limits *explim;
85805         const duk_uint8_t *p;
85806         duk_small_int_t ch;
85807
85808         DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
85809                              (duk_tval *) duk_get_tval(thr, -1),
85810                              (long) radix, (unsigned long) flags));
85811
85812         DUK_ASSERT(radix >= 2 && radix <= 36);
85813         DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix));
85814
85815         /*
85816          *  Preliminaries: trim, sign, Infinity check
85817          *
85818          *  We rely on the interned string having a NUL terminator, which will
85819          *  cause a parse failure wherever it is encountered.  As a result, we
85820          *  don't need separate pointer checks.
85821          *
85822          *  There is no special parsing for 'NaN' in the specification although
85823          *  'Infinity' (with an optional sign) is allowed in some contexts.
85824          *  Some contexts allow plus/minus sign, while others only allow the
85825          *  minus sign (like JSON.parse()).
85826          *
85827          *  Automatic hex number detection (leading '0x' or '0X') and octal
85828          *  number detection (leading '0' followed by at least one octal digit)
85829          *  is done here too.
85830          *
85831          *  Symbols are not explicitly rejected here (that's up to the caller).
85832          *  If a symbol were passed here, it should ultimately safely fail
85833          *  parsing due to a syntax error.
85834          */
85835
85836         if (flags & DUK_S2N_FLAG_TRIM_WHITE) {
85837                 /* Leading / trailing whitespace is sometimes accepted and
85838                  * sometimes not.  After white space trimming, all valid input
85839                  * characters are pure ASCII.
85840                  */
85841                 duk_trim(thr, -1);
85842         }
85843         h_str = duk_require_hstring(thr, -1);
85844         DUK_ASSERT(h_str != NULL);
85845         p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
85846
85847         neg = 0;
85848         ch = *p;
85849         if (ch == (duk_small_int_t) '+') {
85850                 if ((flags & DUK_S2N_FLAG_ALLOW_PLUS) == 0) {
85851                         DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed"));
85852                         goto parse_fail;
85853                 }
85854                 p++;
85855         } else if (ch == (duk_small_int_t) '-') {
85856                 if ((flags & DUK_S2N_FLAG_ALLOW_MINUS) == 0) {
85857                         DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed"));
85858                         goto parse_fail;
85859                 }
85860                 p++;
85861                 neg = 1;
85862         }
85863
85864         if ((flags & DUK_S2N_FLAG_ALLOW_INF) && DUK_STRNCMP((const char *) p, "Infinity", 8) == 0) {
85865                 /* Don't check for Infinity unless the context allows it.
85866                  * 'Infinity' is a valid integer literal in e.g. base-36:
85867                  *
85868                  *   parseInt('Infinity', 36)
85869                  *   1461559270678
85870                  */
85871
85872                 if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0 && p[8] != DUK_ASC_NUL) {
85873                         DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
85874                         goto parse_fail;
85875                 } else {
85876                         res = DUK_DOUBLE_INFINITY;
85877                         goto negcheck_and_ret;
85878                 }
85879         }
85880         ch = *p;
85881         if (ch == (duk_small_int_t) '0') {
85882                 duk_small_int_t detect_radix = 0;
85883                 ch = DUK_LOWERCASE_CHAR_ASCII(p[1]);  /* 'x' or 'X' -> 'x' */
85884                 if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT) && ch == DUK_ASC_LC_X) {
85885                         DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent"));
85886                         detect_radix = 16;
85887 #if 0
85888                 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT) &&
85889                            (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
85890                         DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent"));
85891                         detect_radix = 8;
85892
85893                         /* NOTE: if this legacy octal case is added back, it has
85894                          * different flags and 'p' advance so this needs to be
85895                          * reworked.
85896                          */
85897                         flags |= DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO;  /* interpret e.g. '09' as '0', not NaN */
85898                         p += 1;
85899 #endif
85900                 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) && ch == DUK_ASC_LC_O) {
85901                         DUK_DDD(DUK_DDDPRINT("detected 0o oct prefix, changing radix and preventing fractions and exponent"));
85902                         detect_radix = 8;
85903                 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT) && ch == DUK_ASC_LC_B) {
85904                         DUK_DDD(DUK_DDDPRINT("detected 0b bin prefix, changing radix and preventing fractions and exponent"));
85905                         detect_radix = 2;
85906                 }
85907                 if (detect_radix > 0) {
85908                         radix = detect_radix;
85909                         /* Clear empty as zero flag: interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
85910                         flags &= ~(DUK_S2N_FLAG_ALLOW_EXP | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
85911                                    DUK_S2N_FLAG_ALLOW_FRAC | DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
85912                                    DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
85913                         flags |= DUK_S2N_FLAG_ALLOW_LEADING_ZERO;  /* allow e.g. '0x0009' and '0b00010001' */
85914                         p += 2;
85915                 }
85916         }
85917
85918         /*
85919          *  Scan number and setup for Dragon4.
85920          *
85921          *  The fast path case is detected during setup: an integer which
85922          *  can be converted without rounding, no net exponent.  The fast
85923          *  path could be implemented as a separate scan, but may not really
85924          *  be worth it: the multiplications for building 'f' are not
85925          *  expensive when 'f' is small.
85926          *
85927          *  The significand ('f') must contain enough bits of (apparent)
85928          *  accuracy, so that Dragon4 will generate enough binary output digits.
85929          *  For decimal numbers, this means generating a 20-digit significand,
85930          *  which should yield enough practical accuracy to parse IEEE doubles.
85931          *  In fact, the ECMAScript specification explicitly allows an
85932          *  implementation to treat digits beyond 20 as zeroes (and even
85933          *  to round the 20th digit upwards).  For non-decimal numbers, the
85934          *  appropriate number of digits has been precomputed for comparable
85935          *  accuracy.
85936          *
85937          *  Digit counts:
85938          *
85939          *    [ dig_lzero ]
85940          *      |
85941          *     .+-..---[ dig_prec ]----.
85942          *     |  ||                   |
85943          *     0000123.456789012345678901234567890e+123456
85944          *     |     | |                         |  |    |
85945          *     `--+--' `------[ dig_frac ]-------'  `-+--'
85946          *        |                                   |
85947          *    [ dig_whole ]                       [ dig_expt ]
85948          *
85949          *    dig_frac and dig_expt are -1 if not present
85950          *    dig_lzero is only computed for whole number part
85951          *
85952          *  Parsing state
85953          *
85954          *     Parsing whole part      dig_frac < 0 AND dig_expt < 0
85955          *     Parsing fraction part   dig_frac >= 0 AND dig_expt < 0
85956          *     Parsing exponent part   dig_expt >= 0   (dig_frac may be < 0 or >= 0)
85957          *
85958          *  Note: in case we hit an implementation limit (like exponent range),
85959          *  we should throw an error, NOT return NaN or Infinity.  Even with
85960          *  very large exponent (or significand) values the final result may be
85961          *  finite, so NaN/Infinity would be incorrect.
85962          */
85963
85964         duk__bi_set_small(&nc_ctx->f, 0);
85965         dig_prec = 0;
85966         dig_lzero = 0;
85967         dig_whole = 0;
85968         dig_frac = -1;
85969         dig_expt = -1;
85970         expt = 0;
85971         expt_adj = 0;  /* essentially tracks digit position of lowest 'f' digit */
85972         expt_neg = 0;
85973         for (;;) {
85974                 ch = *p++;
85975
85976                 DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, "
85977                                      "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld",
85978                                      (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
85979                                      (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac,
85980                                      (long) dig_expt, (long) dig_lzero, (long) dig_prec));
85981                 DUK__BI_PRINT("f", &nc_ctx->f);
85982
85983                 /* Most common cases first. */
85984                 if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
85985                         dig = (duk_small_int_t) ch - '0' + 0;
85986                 } else if (ch == (duk_small_int_t) '.') {
85987                         /* A leading digit is not required in some cases, e.g. accept ".123".
85988                          * In other cases (JSON.parse()) a leading digit is required.  This
85989                          * is checked for after the loop.
85990                          */
85991                         if (dig_frac >= 0 || dig_expt >= 0) {
85992                                 if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
85993                                         DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)"));
85994                                         break;
85995                                 } else {
85996                                         DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed"));
85997                                         goto parse_fail;
85998                                 }
85999                         }
86000
86001                         if ((flags & DUK_S2N_FLAG_ALLOW_FRAC) == 0) {
86002                                 /* Some contexts don't allow fractions at all; this can't be a
86003                                  * post-check because the state ('f' and expt) would be incorrect.
86004                                  */
86005                                 if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
86006                                         DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)"));
86007                                         break;
86008                                 } else {
86009                                         DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed"));
86010                                 }
86011                         }
86012
86013                         DUK_DDD(DUK_DDDPRINT("start fraction part"));
86014                         dig_frac = 0;
86015                         continue;
86016                 } else if (ch == (duk_small_int_t) 0) {
86017                         DUK_DDD(DUK_DDDPRINT("NUL termination"));
86018                         break;
86019                 } else if ((flags & DUK_S2N_FLAG_ALLOW_EXP) &&
86020                            dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
86021                         /* Note: we don't parse back exponent notation for anything else
86022                          * than radix 10, so this is not an ambiguous check (e.g. hex
86023                          * exponent values may have 'e' either as a significand digit
86024                          * or as an exponent separator).
86025                          *
86026                          * If the exponent separator occurs twice, 'e' will be interpreted
86027                          * as a digit (= 14) and will be rejected as an invalid decimal
86028                          * digit.
86029                          */
86030
86031                         DUK_DDD(DUK_DDDPRINT("start exponent part"));
86032
86033                         /* Exponent without a sign or with a +/- sign is accepted
86034                          * by all call sites (even JSON.parse()).
86035                          */
86036                         ch = *p;
86037                         if (ch == (duk_small_int_t) '-') {
86038                                 expt_neg = 1;
86039                                 p++;
86040                         } else if (ch == (duk_small_int_t) '+') {
86041                                 p++;
86042                         }
86043                         dig_expt = 0;
86044                         continue;
86045                 } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') {
86046                         dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a);
86047                 } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') {
86048                         dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a);
86049                 } else {
86050                         dig = 255;  /* triggers garbage digit check below */
86051                 }
86052                 DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
86053
86054                 if (dig >= radix) {
86055                         if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
86056                                 DUK_DDD(DUK_DDDPRINT("garbage termination"));
86057                                 break;
86058                         } else {
86059                                 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit"));
86060                                 goto parse_fail;
86061                         }
86062                 }
86063
86064                 if (dig_expt < 0) {
86065                         /* whole or fraction digit */
86066
86067                         if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
86068                                 /* significant from precision perspective */
86069
86070                                 duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f);
86071                                 if (f_zero && dig == 0) {
86072                                         /* Leading zero is not counted towards precision digits; not
86073                                          * in the integer part, nor in the fraction part.
86074                                          */
86075                                         if (dig_frac < 0) {
86076                                                 dig_lzero++;
86077                                         }
86078                                 } else {
86079                                         /* XXX: join these ops (multiply-accumulate), but only if
86080                                          * code footprint decreases.
86081                                          */
86082                                         duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, (duk_uint32_t) radix);
86083                                         duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, (duk_uint32_t) dig);
86084                                         dig_prec++;
86085                                 }
86086                         } else {
86087                                 /* Ignore digits beyond a radix-specific limit, but note them
86088                                  * in expt_adj.
86089                                  */
86090                                 expt_adj++;
86091                         }
86092
86093                         if (dig_frac >= 0) {
86094                                 dig_frac++;
86095                                 expt_adj--;
86096                         } else {
86097                                 dig_whole++;
86098                         }
86099                 } else {
86100                         /* exponent digit */
86101
86102                         DUK_ASSERT(radix == 10);
86103                         expt = expt * radix + dig;
86104                         if (expt > DUK_S2N_MAX_EXPONENT) {
86105                                 /* Impose a reasonable exponent limit, so that exp
86106                                  * doesn't need to get tracked using a bigint.
86107                                  */
86108                                 DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large"));
86109                                 goto parse_explimit_error;
86110                         }
86111                         dig_expt++;
86112                 }
86113         }
86114
86115         /* Leading zero. */
86116
86117         if (dig_lzero > 0 && dig_whole > 1) {
86118                 if ((flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO) == 0) {
86119                         DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part"));
86120                         goto parse_fail;
86121                 }
86122         }
86123
86124         /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */
86125
86126         if (dig_whole == 0) {
86127                 if (dig_frac == 0) {
86128                         /* "." is not accepted in any format */
86129                         DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits"));
86130                         goto parse_fail;
86131                 } else if (dig_frac > 0) {
86132                         /* ".123" */
86133                         if ((flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC) == 0) {
86134                                 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without "
86135                                                      "leading integer digit(s)"));
86136                                 goto parse_fail;
86137                         }
86138                 } else {
86139                         /* empty ("") is allowed in some formats (e.g. Number(''), as zero */
86140                         if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO) == 0) {
86141                                 DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)"));
86142                                 goto parse_fail;
86143                         }
86144                 }
86145         } else {
86146                 if (dig_frac == 0) {
86147                         /* "123." is allowed in some formats */
86148                         if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC) == 0) {
86149                                 DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions"));
86150                                 goto parse_fail;
86151                         }
86152                 } else if (dig_frac > 0) {
86153                         /* "123.456" */
86154                         ;
86155                 } else {
86156                         /* "123" */
86157                         ;
86158                 }
86159         }
86160
86161         /* Exponent without digits (e.g. "1e" or "1e+").  If trailing garbage is
86162          * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0).
86163          */
86164
86165         if (dig_expt == 0) {
86166                 if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0) {
86167                         DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent"));
86168                         goto parse_fail;
86169                 }
86170                 DUK_ASSERT(expt == 0);
86171         }
86172
86173         if (expt_neg) {
86174                 expt = -expt;
86175         }
86176         DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld",
86177                              (long) expt, (long) expt_adj, (long) (expt + expt_adj)));
86178         expt += expt_adj;
86179
86180         /* Fast path check. */
86181
86182         if (nc_ctx->f.n <= 1 &&   /* 32-bit value */
86183             expt == 0    /* no net exponent */) {
86184                 /* Fast path is triggered for no exponent and also for balanced exponent
86185                  * and fraction parts, e.g. for "1.23e2" == "123".  Remember to respect
86186                  * zero sign.
86187                  */
86188
86189                 /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */
86190                 DUK_DDD(DUK_DDDPRINT("fast path number parse"));
86191                 if (nc_ctx->f.n == 1) {
86192                         res = (double) nc_ctx->f.v[0];
86193                 } else {
86194                         res = 0.0;
86195                 }
86196                 goto negcheck_and_ret;
86197         }
86198
86199         /* Significand ('f') padding. */
86200
86201         while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
86202                 /* Pad significand with "virtual" zero digits so that Dragon4 will
86203                  * have enough (apparent) precision to work with.
86204                  */
86205                 DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
86206                 duk__bi_mul_small_copy(&nc_ctx->f, (duk_uint32_t) radix, &nc_ctx->t1);
86207                 DUK__BI_PRINT("f", &nc_ctx->f);
86208                 expt--;
86209                 dig_prec++;
86210         }
86211
86212         DUK_DDD(DUK_DDDPRINT("final exponent: %ld", (long) expt));
86213
86214         /* Detect zero special case. */
86215
86216         if (nc_ctx->f.n == 0) {
86217                 /* This may happen even after the fast path check, if exponent is
86218                  * not balanced (e.g. "0e1").  Remember to respect zero sign.
86219                  */
86220                 DUK_DDD(DUK_DDDPRINT("significand is zero"));
86221                 res = 0.0;
86222                 goto negcheck_and_ret;
86223         }
86224
86225
86226         /* Quick reject of too large or too small exponents.  This check
86227          * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity)
86228          * so zero check must be above.
86229          */
86230
86231         explim = &duk__str2num_exp_limits[radix - 2];
86232         if (expt > explim->upper) {
86233                 DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite"));
86234                 res = (duk_double_t) DUK_DOUBLE_INFINITY;
86235                 goto negcheck_and_ret;
86236         } else if (expt < explim->lower) {
86237                 DUK_DDD(DUK_DDDPRINT("exponent too small -> zero"));
86238                 res = (duk_double_t) 0.0;
86239                 goto negcheck_and_ret;
86240         }
86241
86242         nc_ctx->is_s2n = 1;
86243         nc_ctx->e = expt;
86244         nc_ctx->b = radix;
86245         nc_ctx->B = 2;
86246         nc_ctx->is_fixed = 1;
86247         nc_ctx->abs_pos = 0;
86248         nc_ctx->req_digits = 53 + 1;
86249
86250         DUK__BI_PRINT("f", &nc_ctx->f);
86251         DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
86252
86253         /*
86254          *  Dragon4 slow path (binary) digit generation.
86255          *  An extra digit is generated for rounding.
86256          */
86257
86258         duk__dragon4_prepare(nc_ctx);  /* setup many variables in nc_ctx */
86259
86260         DUK_DDD(DUK_DDDPRINT("after prepare:"));
86261         DUK__BI_PRINT("r", &nc_ctx->r);
86262         DUK__BI_PRINT("s", &nc_ctx->s);
86263         DUK__BI_PRINT("mp", &nc_ctx->mp);
86264         DUK__BI_PRINT("mm", &nc_ctx->mm);
86265
86266         duk__dragon4_scale(nc_ctx);
86267
86268         DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
86269         DUK__BI_PRINT("r", &nc_ctx->r);
86270         DUK__BI_PRINT("s", &nc_ctx->s);
86271         DUK__BI_PRINT("mp", &nc_ctx->mp);
86272         DUK__BI_PRINT("mm", &nc_ctx->mm);
86273
86274         duk__dragon4_generate(nc_ctx);
86275
86276         DUK_ASSERT(nc_ctx->count == 53 + 1);
86277
86278         /*
86279          *  Convert binary digits into an IEEE double.  Need to handle
86280          *  denormals and rounding correctly.
86281          *
86282          *  Some call sites currently assume the result is always a
86283          *  non-fastint double.  If this is changed, check all call
86284          *  sites.
86285          */
86286
86287         duk__dragon4_ctx_to_double(nc_ctx, &res);
86288         goto negcheck_and_ret;
86289
86290  negcheck_and_ret:
86291         if (neg) {
86292                 res = -res;
86293         }
86294         duk_pop(thr);
86295         duk_push_number(thr, (double) res);
86296         DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(thr, -1)));
86297         return;
86298
86299  parse_fail:
86300         DUK_DDD(DUK_DDDPRINT("parse failed"));
86301         duk_pop(thr);
86302         duk_push_nan(thr);
86303         return;
86304
86305  parse_explimit_error:
86306         DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value"));
86307         DUK_ERROR_RANGE(thr, "exponent too large");
86308         DUK_WO_NORETURN(return;);
86309 }
86310
86311 /* automatic undefs */
86312 #undef DUK__BI_MAX_PARTS
86313 #undef DUK__BI_PRINT
86314 #undef DUK__DIGITCHAR
86315 #undef DUK__DRAGON4_OUTPUT_PREINC
86316 #undef DUK__IEEE_DOUBLE_EXP_BIAS
86317 #undef DUK__IEEE_DOUBLE_EXP_MIN
86318 #undef DUK__MAX_FORMATTED_LENGTH
86319 #undef DUK__MAX_OUTPUT_DIGITS
86320 #undef DUK__NO_EXP
86321 #undef DUK__NUMCONV_CTX_BIGINTS_SIZE
86322 #undef DUK__NUMCONV_CTX_NUM_BIGINTS
86323 #line 1 "duk_regexp_compiler.c"
86324 /*
86325  *  Regexp compilation.
86326  *
86327  *  See doc/regexp.rst for a discussion of the compilation approach and
86328  *  current limitations.
86329  *
86330  *  Regexp bytecode assumes jumps can be expressed with signed 32-bit
86331  *  integers.  Consequently the bytecode size must not exceed 0x7fffffffL.
86332  *  The implementation casts duk_size_t (buffer size) to duk_(u)int32_t
86333  *  in many places.  Although this could be changed, the bytecode format
86334  *  limit would still prevent regexps exceeding the signed 32-bit limit
86335  *  from working.
86336  *
86337  *  XXX: The implementation does not prevent bytecode from exceeding the
86338  *  maximum supported size.  This could be done by limiting the maximum
86339  *  input string size (assuming an upper bound can be computed for number
86340  *  of bytecode bytes emitted per input byte) or checking buffer maximum
86341  *  size when emitting bytecode (slower).
86342  */
86343
86344 /* #include duk_internal.h -> already included */
86345
86346 #if defined(DUK_USE_REGEXP_SUPPORT)
86347
86348 /*
86349  *  Helper macros
86350  */
86351
86352 #define DUK__RE_INITIAL_BUFSIZE 64
86353
86354 #define DUK__RE_BUFLEN(re_ctx) \
86355         DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw)
86356
86357 /*
86358  *  Disjunction struct: result of parsing a disjunction
86359  */
86360
86361 typedef struct {
86362         /* Number of characters that the atom matches (e.g. 3 for 'abc'),
86363          * -1 if atom is complex and number of matched characters either
86364          * varies or is not known.
86365          */
86366         duk_int32_t charlen;
86367
86368 #if 0
86369         /* These are not needed to implement quantifier capture handling,
86370          * but might be needed at some point.
86371          */
86372
86373         /* re_ctx->captures at start and end of atom parsing.
86374          * Since 'captures' indicates highest capture number emitted
86375          * so far in a DUK_REOP_SAVE, the captures numbers saved by
86376          * the atom are: ]start_captures,end_captures].
86377          */
86378         duk_uint32_t start_captures;
86379         duk_uint32_t end_captures;
86380 #endif
86381 } duk__re_disjunction_info;
86382
86383 /*
86384  *  Encoding helpers
86385  *
86386  *  Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit
86387  *  even though the buffer operations will use duk_size_t.
86388  */
86389
86390 /* XXX: the insert helpers should ensure that the bytecode result is not
86391  * larger than expected (or at least assert for it).  Many things in the
86392  * bytecode, like skip offsets, won't work correctly if the bytecode is
86393  * larger than say 2G.
86394  */
86395
86396 DUK_LOCAL duk_uint32_t duk__encode_i32(duk_int32_t x) {
86397         if (x < 0) {
86398                 return ((duk_uint32_t) (-x)) * 2 + 1;
86399         } else {
86400                 return ((duk_uint32_t) x) * 2;
86401         }
86402 }
86403
86404 /* XXX: return type should probably be duk_size_t, or explicit checks are needed for
86405  * maximum size.
86406  */
86407 DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) {
86408         duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
86409         duk_small_int_t len;
86410
86411         len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
86412         DUK_ASSERT(len >= 0);
86413         DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, (duk_size_t) len);
86414         return (duk_uint32_t) len;
86415 }
86416
86417 DUK_LOCAL void duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
86418         DUK_BW_WRITE_ENSURE_XUTF8(re_ctx->thr, &re_ctx->bw, x);
86419 }
86420
86421 DUK_LOCAL void duk__append_7bit(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
86422 #if defined(DUK_USE_PREFER_SIZE)
86423         duk__append_u32(re_ctx, x);
86424 #else
86425         DUK_ASSERT(x <= 0x7fU);
86426         DUK_BW_WRITE_ENSURE_U8(re_ctx->thr, &re_ctx->bw, (duk_uint8_t) x);
86427 #endif
86428 }
86429
86430 #if 0
86431 DUK_LOCAL void duk__append_2bytes(duk_re_compiler_ctx *re_ctx, duk_uint8_t x, duk_uint8_t y) {
86432         DUK_BW_WRITE_ENSURE_U8_2(re_ctx->thr, &re_ctx->bw, x, y);
86433 }
86434 #endif
86435
86436 DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) {
86437         return duk__insert_u32(re_ctx, offset, duk__encode_i32(x));
86438 }
86439
86440 DUK_LOCAL void duk__append_reop(duk_re_compiler_ctx *re_ctx, duk_uint32_t reop) {
86441         DUK_ASSERT(reop <= 0x7fU);
86442         (void) duk__append_7bit(re_ctx, reop);
86443 }
86444
86445 #if 0  /* unused */
86446 DUK_LOCAL void duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
86447         duk__append_u32(re_ctx, duk__encode_i32(x));
86448 }
86449 #endif
86450
86451 /* special helper for emitting u16 lists (used for character ranges for built-in char classes) */
86452 DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) {
86453         /* Call sites don't need the result length so it's not accumulated. */
86454         while (count-- > 0) {
86455                 duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
86456         }
86457 }
86458
86459 DUK_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) {
86460         DUK_BW_INSERT_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, offset, data_offset, data_length);
86461 }
86462
86463 DUK_LOCAL void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
86464         DUK_BW_WRITE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
86465 }
86466
86467 DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
86468         DUK_BW_REMOVE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
86469 }
86470
86471 /*
86472  *  Insert a jump offset at 'offset' to complete an instruction
86473  *  (the jump offset is always the last component of an instruction).
86474  *  The 'skip' argument must be computed relative to 'offset',
86475  *  -without- taking into account the skip field being inserted.
86476  *
86477  *       ... A B C ins X Y Z ...   (ins may be a JUMP, SPLIT1/SPLIT2, etc)
86478  *   =>  ... A B C ins SKIP X Y Z
86479  *
86480  *  Computing the final (adjusted) skip value, which is relative to the
86481  *  first byte of the next instruction, is a bit tricky because of the
86482  *  variable length UTF-8 encoding.  See doc/regexp.rst for discussion.
86483  */
86484 DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) {
86485 #if 0
86486         /* Iterative solution. */
86487         if (skip < 0) {
86488                 duk_small_int_t len;
86489                 /* two encoding attempts suffices */
86490                 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip));
86491                 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len));
86492                 DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len);  /* no change */
86493                 skip -= (duk_int32_t) len;
86494         }
86495 #endif
86496
86497 #if defined(DUK_USE_PREFER_SIZE)
86498         /* Closed form solution, this produces smallest code.
86499          * See re_neg_jump_offset (closed2).
86500          */
86501         if (skip < 0) {
86502                 skip--;
86503                 if (skip < -0x3fL) {
86504                         skip--;
86505                 }
86506                 if (skip < -0x3ffL) {
86507                         skip--;
86508                 }
86509                 if (skip < -0x7fffL) {
86510                         skip--;
86511                 }
86512                 if (skip < -0xfffffL) {
86513                         skip--;
86514                 }
86515                 if (skip < -0x1ffffffL) {
86516                         skip--;
86517                 }
86518                 if (skip < -0x3fffffffL) {
86519                         skip--;
86520                 }
86521         }
86522 #else  /* DUK_USE_PREFER_SIZE */
86523         /* Closed form solution, this produces fastest code.
86524          * See re_neg_jump_offset (closed1).
86525          */
86526         if (skip < 0) {
86527                 if (skip >= -0x3eL) {
86528                         skip -= 1;
86529                 } else if (skip >= -0x3fdL) {
86530                         skip -= 2;
86531                 } else if (skip >= -0x7ffcL) {
86532                         skip -= 3;
86533                 } else if (skip >= -0xffffbL) {
86534                         skip -= 4;
86535                 } else if (skip >= -0x1fffffaL) {
86536                         skip -= 5;
86537                 } else if (skip >= -0x3ffffff9L) {
86538                         skip -= 6;
86539                 } else {
86540                         skip -= 7;
86541                 }
86542         }
86543 #endif  /* DUK_USE_PREFER_SIZE */
86544
86545         return duk__insert_i32(re_ctx, offset, skip);
86546 }
86547
86548 DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) {
86549         return (duk_uint32_t) duk__insert_jump_offset(re_ctx, (duk_uint32_t) DUK__RE_BUFLEN(re_ctx), skip);
86550 }
86551
86552 /*
86553  *  duk_re_range_callback for generating character class ranges.
86554  *
86555  *  When ignoreCase is false, the range is simply emitted as is.  We don't,
86556  *  for instance, eliminate duplicates or overlapping ranges in a character
86557  *  class.
86558  *
86559  *  When ignoreCase is true but the 'direct' flag is set, the caller knows
86560  *  that the range canonicalizes to itself for case insensitive matching,
86561  *  so the range is emitted as is.  This is mainly useful for built-in ranges
86562  *  like \W.
86563  *
86564  *  Otherwise, when ignoreCase is true, the range needs to be normalized
86565  *  through canonicalization.  Unfortunately a canonicalized version of a
86566  *  continuous range is not necessarily continuous (e.g. [x-{] is continuous
86567  *  but [X-{] is not).  As a result, a single input range may expand to a lot
86568  *  of output ranges.  The current algorithm creates the canonicalized ranges
86569  *  footprint efficiently at the cost of compile time execution time; see
86570  *  doc/regexp.rst for discussion, and some more details below.
86571  *
86572  *  Note that the ctx->nranges is a context-wide temporary value.  This is OK
86573  *  because there cannot be multiple character classes being parsed
86574  *  simultaneously.
86575  *
86576  *  More detail on canonicalization:
86577  *
86578  *  Conceptually, a range is canonicalized by scanning the entire range,
86579  *  normalizing each codepoint by converting it to uppercase, and generating
86580  *  a set of result ranges.
86581  *
86582  *  Ideally a minimal set of output ranges would be emitted by merging all
86583  *  possible ranges even if they're emitted out of sequence.  Because the
86584  *  input string is also case normalized during matching, some codepoints
86585  *  never occur at runtime; these "don't care" codepoints can be included or
86586  *  excluded from ranges when merging/optimizing ranges.
86587  *
86588  *  The current algorithm does not do optimal range merging.  Rather, output
86589  *  codepoints are generated in sequence, and when the output codepoints are
86590  *  continuous (CP, CP+1, CP+2, ...), they are merged locally into as large a
86591  *  range as possible.  A small canonicalization bitmap is used to reduce
86592  *  actual codepoint canonicalizations which are quite slow at present.  The
86593  *  bitmap provides a "codepoint block is continuous with respect to
86594  *  canonicalization" for N-codepoint blocks.  This allows blocks to be
86595  *  skipped quickly.
86596  *
86597  *  There are a number of shortcomings and future work here:
86598  *
86599  *    - Individual codepoint normalizations are slow because they involve
86600  *      walking bit-packed rules without a lookup index.
86601  *
86602  *    - The conceptual algorithm needs to canonicalize every codepoint in the
86603  *      input range to figure out the output range(s).  Even with the small
86604  *      canonicalization bitmap the algorithm runs quite slowly for worst case
86605  *      inputs.  There are many data structure alternatives to improve this.
86606  *
86607  *    - While the current algorithm generates maximal output ranges when the
86608  *      output codepoints are emitted linearly, output ranges are not sorted or
86609  *      merged otherwise.  In the worst case a lot of ranges are emitted when
86610  *      most of the ranges could be merged.  In this process one could take
86611  *      advantage of "don't care" codepoints, which are never matched against at
86612  *      runtime due to canonicalization of input codepoints before comparison,
86613  *      to merge otherwise discontinuous output ranges.
86614  *
86615  *    - The runtime data structure is just a linear list of ranges to match
86616  *      against.  This can be quite slow if there are a lot of output ranges.
86617  *      There are various ways to make matching against the ranges faster,
86618  *      e.g. sorting the ranges and using a binary search; skip lists; tree
86619  *      based representations; full or approximate codepoint bitmaps, etc.
86620  *
86621  *    - Only BMP is supported, codepoints above BMP are assumed to canonicalize
86622  *      to themselves.  For now this is one place where we don't want to
86623  *      support chars outside the BMP, because the exhaustive search would be
86624  *      massively larger.  It would be possible to support non-BMP with a
86625  *      different algorithm, or perhaps doing case normalization only at match
86626  *      time.
86627  */
86628
86629 DUK_LOCAL void duk__regexp_emit_range(duk_re_compiler_ctx *re_ctx, duk_codepoint_t r1, duk_codepoint_t r2) {
86630         DUK_ASSERT(r2 >= r1);
86631         duk__append_u32(re_ctx, (duk_uint32_t) r1);
86632         duk__append_u32(re_ctx, (duk_uint32_t) r2);
86633         re_ctx->nranges++;
86634 }
86635
86636 #if defined(DUK_USE_REGEXP_CANON_BITMAP)
86637 /* Find next canonicalization discontinuity (conservative estimate) starting
86638  * from 'start', not exceeding 'end'.  If continuity is fine up to 'end'
86639  * inclusive, returns end.  Minimum possible return value is start.
86640  */
86641 DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) {
86642         duk_uint_t start_blk;
86643         duk_uint_t end_blk;
86644         duk_uint_t blk;
86645         duk_uint_t offset;
86646         duk_uint8_t mask;
86647
86648         /* Inclusive block range. */
86649         DUK_ASSERT(start >= 0);
86650         DUK_ASSERT(end >= 0);
86651         DUK_ASSERT(end >= start);
86652         start_blk = (duk_uint_t) (start >> DUK_CANON_BITMAP_BLKSHIFT);
86653         end_blk = (duk_uint_t) (end >> DUK_CANON_BITMAP_BLKSHIFT);
86654
86655         for (blk = start_blk; blk <= end_blk; blk++) {
86656                 offset = blk >> 3;
86657                 mask = 1U << (blk & 0x07);
86658                 if (offset >= sizeof(duk_unicode_re_canon_bitmap)) {
86659                         /* Reached non-BMP range which is assumed continuous. */
86660                         return end;
86661                 }
86662                 DUK_ASSERT(offset < sizeof(duk_unicode_re_canon_bitmap));
86663                 if ((duk_unicode_re_canon_bitmap[offset] & mask) == 0) {
86664                         /* Block is discontinuous, continuity is guaranteed
86665                          * only up to end of previous block (+1 for exclusive
86666                          * return value => start of current block).  Start
86667                          * block requires special handling.
86668                          */
86669                         if (blk > start_blk) {
86670                                 return (duk_codepoint_t) (blk << DUK_CANON_BITMAP_BLKSHIFT);
86671                         } else {
86672                                 return start;
86673                         }
86674                 }
86675         }
86676         DUK_ASSERT(blk == end_blk + 1);  /* Reached end block which is continuous. */
86677         return end;
86678 }
86679 #else  /* DUK_USE_REGEXP_CANON_BITMAP */
86680 DUK_LOCAL duk_codepoint_t duk__re_canon_next_discontinuity(duk_codepoint_t start, duk_codepoint_t end) {
86681         DUK_ASSERT(start >= 0);
86682         DUK_ASSERT(end >= 0);
86683         DUK_ASSERT(end >= start);
86684         if (start >= 0x10000) {
86685                 /* Even without the bitmap, treat non-BMP as continuous. */
86686                 return end;
86687         }
86688         return start;
86689 }
86690 #endif  /* DUK_USE_REGEXP_CANON_BITMAP */
86691
86692 DUK_LOCAL void duk__regexp_generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
86693         duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
86694         duk_codepoint_t r_start;
86695         duk_codepoint_t r_end;
86696         duk_codepoint_t i;
86697         duk_codepoint_t t;
86698         duk_codepoint_t r_disc;
86699
86700         DUK_DD(DUK_DDPRINT("duk__regexp_generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
86701                            (void *) re_ctx, (long) r1, (long) r2, (long) direct));
86702
86703         DUK_ASSERT(r2 >= r1);  /* SyntaxError for out of order range. */
86704
86705         if (direct || (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) == 0) {
86706                 DUK_DD(DUK_DDPRINT("direct or not case sensitive, emit range: [%ld,%ld]", (long) r1, (long) r2));
86707                 duk__regexp_emit_range(re_ctx, r1, r2);
86708                 return;
86709         }
86710
86711         DUK_DD(DUK_DDPRINT("case sensitive, process range: [%ld,%ld]", (long) r1, (long) r2));
86712
86713         r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
86714         r_end = r_start;
86715
86716         for (i = r1 + 1; i <= r2;) {
86717                 /* Input codepoint space processed up to i-1, and
86718                  * current range in r_{start,end} is up-to-date
86719                  * (inclusive) and may either break or continue.
86720                  */
86721                 r_disc = duk__re_canon_next_discontinuity(i, r2);
86722                 DUK_ASSERT(r_disc >= i);
86723                 DUK_ASSERT(r_disc <= r2);
86724
86725                 r_end += r_disc - i;  /* May be zero. */
86726                 t = duk_unicode_re_canonicalize_char(re_ctx->thr, r_disc);
86727                 if (t == r_end + 1) {
86728                         /* Not actually a discontinuity, continue range
86729                          * to r_disc and recheck.
86730                          */
86731                         r_end = t;
86732                 } else {
86733                         duk__regexp_emit_range(re_ctx, r_start, r_end);
86734                         r_start = t;
86735                         r_end = t;
86736                 }
86737                 i = r_disc + 1;  /* Guarantees progress. */
86738         }
86739         duk__regexp_emit_range(re_ctx, r_start, r_end);
86740
86741 #if 0  /* Exhaustive search, very slow. */
86742         r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
86743         r_end = r_start;
86744         for (i = r1 + 1; i <= r2; i++) {
86745                 t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
86746                 if (t == r_end + 1) {
86747                         r_end = t;
86748                 } else {
86749                         DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
86750                         duk__append_u32(re_ctx, (duk_uint32_t) r_start);
86751                         duk__append_u32(re_ctx, (duk_uint32_t) r_end);
86752                         re_ctx->nranges++;
86753                         r_start = t;
86754                         r_end = t;
86755                 }
86756         }
86757         DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
86758         duk__append_u32(re_ctx, (duk_uint32_t) r_start);
86759         duk__append_u32(re_ctx, (duk_uint32_t) r_end);
86760         re_ctx->nranges++;
86761 #endif
86762 }
86763
86764 /*
86765  *  Parse regexp Disjunction.  Most of regexp compilation happens here.
86766  *
86767  *  Handles Disjunction, Alternative, and Term productions directly without
86768  *  recursion.  The only constructs requiring recursion are positive/negative
86769  *  lookaheads, capturing parentheses, and non-capturing parentheses.
86770  *
86771  *  The function determines whether the entire disjunction is a 'simple atom'
86772  *  (see doc/regexp.rst discussion on 'simple quantifiers') and if so,
86773  *  returns the atom character length which is needed by the caller to keep
86774  *  track of its own atom character length.  A disjunction with more than one
86775  *  alternative is never considered a simple atom (although in some cases
86776  *  that might be the case).
86777  *
86778  *  Return value: simple atom character length or < 0 if not a simple atom.
86779  *  Appends the bytecode for the disjunction matcher to the end of the temp
86780  *  buffer.
86781  *
86782  *  Regexp top level structure is:
86783  *
86784  *    Disjunction = Term*
86785  *                | Term* | Disjunction
86786  *
86787  *    Term = Assertion
86788  *         | Atom
86789  *         | Atom Quantifier
86790  *
86791  *  An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/).
86792  *
86793  *  Notes:
86794  *
86795  *    * Tracking of the 'simple-ness' of the current atom vs. the entire
86796  *      disjunction are separate matters.  For instance, the disjunction
86797  *      may be complex, but individual atoms may be simple.  Furthermore,
86798  *      simple quantifiers are used whenever possible, even if the
86799  *      disjunction as a whole is complex.
86800  *
86801  *    * The estimate of whether an atom is simple is conservative now,
86802  *      and it would be possible to expand it.  For instance, captures
86803  *      cause the disjunction to be marked complex, even though captures
86804  *      -can- be handled by simple quantifiers with some minor modifications.
86805  *
86806  *    * Disjunction 'tainting' as 'complex' is handled at the end of the
86807  *      main for loop collectively for atoms.  Assertions, quantifiers,
86808  *      and '|' tokens need to taint the result manually if necessary.
86809  *      Assertions cannot add to result char length, only atoms (and
86810  *      quantifiers) can; currently quantifiers will taint the result
86811  *      as complex though.
86812  */
86813
86814 DUK_LOCAL const duk_uint16_t * const duk__re_range_lookup1[3] = {
86815         duk_unicode_re_ranges_digit,
86816         duk_unicode_re_ranges_white,
86817         duk_unicode_re_ranges_wordchar
86818 };
86819 DUK_LOCAL const duk_uint8_t duk__re_range_lookup2[3] = {
86820         sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)),
86821         sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)),
86822         sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t))
86823 };
86824
86825 DUK_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) {
86826 #if 0
86827         DUK_ASSERT(re_op <= 0x7fUL);
86828         DUK_ASSERT(count <= 0x7fUL);
86829         duk__append_2bytes(re_ctx, (duk_uint8_t) re_op, (duk_uint8_t) count);
86830 #endif
86831         duk__append_reop(re_ctx, re_op);
86832         duk__append_7bit(re_ctx, count);
86833         duk__append_u16_list(re_ctx, ranges, count * 2);
86834 }
86835
86836 DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) {
86837         duk_int32_t atom_start_offset = -1;                   /* negative -> no atom matched on previous round */
86838         duk_int32_t atom_char_length = 0;                     /* negative -> complex atom */
86839         duk_uint32_t atom_start_captures = re_ctx->captures;  /* value of re_ctx->captures at start of atom */
86840         duk_int32_t unpatched_disjunction_split = -1;
86841         duk_int32_t unpatched_disjunction_jump = -1;
86842         duk_uint32_t entry_offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
86843         duk_int32_t res_charlen = 0;  /* -1 if disjunction is complex, char length if simple */
86844         duk__re_disjunction_info tmp_disj;
86845
86846         DUK_ASSERT(out_atom_info != NULL);
86847
86848         if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
86849                 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT);
86850                 DUK_WO_NORETURN(return;);
86851         }
86852         re_ctx->recursion_depth++;
86853
86854 #if 0
86855         out_atom_info->start_captures = re_ctx->captures;
86856 #endif
86857
86858         for (;;) {
86859                 /* atom_char_length, atom_start_offset, atom_start_offset reflect the
86860                  * atom matched on the previous loop.  If a quantifier is encountered
86861                  * on this loop, these are needed to handle the quantifier correctly.
86862                  * new_atom_char_length etc are for the atom parsed on this round;
86863                  * they're written to atom_char_length etc at the end of the round.
86864                  */
86865                 duk_int32_t new_atom_char_length;   /* char length of the atom parsed in this loop */
86866                 duk_int32_t new_atom_start_offset;  /* bytecode start offset of the atom parsed in this loop
86867                                                      * (allows quantifiers to copy the atom bytecode)
86868                                                      */
86869                 duk_uint32_t new_atom_start_captures;  /* re_ctx->captures at the start of the atom parsed in this loop */
86870
86871                 duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token);
86872
86873                 DUK_DD(DUK_DDPRINT("re token: %ld (num=%ld, char=%c)",
86874                                    (long) re_ctx->curr_token.t,
86875                                    (long) re_ctx->curr_token.num,
86876                                    (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ?
86877                                    (int) re_ctx->curr_token.num : (int) '?'));
86878
86879                 /* set by atom case clauses */
86880                 new_atom_start_offset = -1;
86881                 new_atom_char_length = -1;
86882                 new_atom_start_captures = re_ctx->captures;
86883
86884                 switch (re_ctx->curr_token.t) {
86885                 case DUK_RETOK_DISJUNCTION: {
86886                         /*
86887                          *  The handling here is a bit tricky.  If a previous '|' has been processed,
86888                          *  we have a pending split1 and a pending jump (for a previous match).  These
86889                          *  need to be back-patched carefully.  See docs for a detailed example.
86890                          */
86891
86892                         /* patch pending jump and split */
86893                         if (unpatched_disjunction_jump >= 0) {
86894                                 duk_uint32_t offset;
86895
86896                                 DUK_ASSERT(unpatched_disjunction_split >= 0);
86897                                 offset = (duk_uint32_t) unpatched_disjunction_jump;
86898                                 offset += duk__insert_jump_offset(re_ctx,
86899                                                                   offset,
86900                                                                   (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
86901                                 /* offset is now target of the pending split (right after jump) */
86902                                 duk__insert_jump_offset(re_ctx,
86903                                                         (duk_uint32_t) unpatched_disjunction_split,
86904                                                         (duk_int32_t) offset - unpatched_disjunction_split);
86905                         }
86906
86907                         /* add a new pending split to the beginning of the entire disjunction */
86908                         (void) duk__insert_u32(re_ctx,
86909                                                entry_offset,
86910                                                DUK_REOP_SPLIT1);   /* prefer direct execution */
86911                         unpatched_disjunction_split = (duk_int32_t) (entry_offset + 1);   /* +1 for opcode */
86912
86913                         /* add a new pending match jump for latest finished alternative */
86914                         duk__append_reop(re_ctx, DUK_REOP_JUMP);
86915                         unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
86916
86917                         /* 'taint' result as complex */
86918                         res_charlen = -1;
86919                         break;
86920                 }
86921                 case DUK_RETOK_QUANTIFIER: {
86922                         if (atom_start_offset < 0) {
86923                                 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM);
86924                                 DUK_WO_NORETURN(return;);
86925                         }
86926                         if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) {
86927                                 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES);
86928                                 DUK_WO_NORETURN(return;);
86929                         }
86930                         if (atom_char_length >= 0) {
86931                                 /*
86932                                  *  Simple atom
86933                                  *
86934                                  *  If atom_char_length is zero, we'll have unbounded execution time for e.g.
86935                                  *  /()*x/.exec('x').  We can't just skip the match because it might have some
86936                                  *  side effects (for instance, if we allowed captures in simple atoms, the
86937                                  *  capture needs to happen).  The simple solution below is to force the
86938                                  *  quantifier to match at most once, since the additional matches have no effect.
86939                                  *
86940                                  *  With a simple atom there can be no capture groups, so no captures need
86941                                  *  to be reset.
86942                                  */
86943                                 duk_int32_t atom_code_length;
86944                                 duk_uint32_t offset;
86945                                 duk_uint32_t qmin, qmax;
86946
86947                                 qmin = re_ctx->curr_token.qmin;
86948                                 qmax = re_ctx->curr_token.qmax;
86949                                 if (atom_char_length == 0) {
86950                                         /* qmin and qmax will be 0 or 1 */
86951                                         if (qmin > 1) {
86952                                                 qmin = 1;
86953                                         }
86954                                         if (qmax > 1) {
86955                                                 qmax = 1;
86956                                         }
86957                                 }
86958
86959                                 duk__append_reop(re_ctx, DUK_REOP_MATCH);   /* complete 'sub atom' */
86960                                 atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (duk_size_t) atom_start_offset);
86961
86962                                 offset = (duk_uint32_t) atom_start_offset;
86963                                 if (re_ctx->curr_token.greedy) {
86964                                         offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
86965                                         offset += duk__insert_u32(re_ctx, offset, qmin);
86966                                         offset += duk__insert_u32(re_ctx, offset, qmax);
86967                                         offset += duk__insert_u32(re_ctx, offset, (duk_uint32_t) atom_char_length);
86968                                         offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
86969                                 } else {
86970                                         offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
86971                                         offset += duk__insert_u32(re_ctx, offset, qmin);
86972                                         offset += duk__insert_u32(re_ctx, offset, qmax);
86973                                         offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
86974                                 }
86975                                 DUK_UNREF(offset);  /* silence scan-build warning */
86976                         } else {
86977                                 /*
86978                                  *  Complex atom
86979                                  *
86980                                  *  The original code is used as a template, and removed at the end
86981                                  *  (this differs from the handling of simple quantifiers).
86982                                  *
86983                                  *  NOTE: there is no current solution for empty atoms in complex
86984                                  *  quantifiers.  This would need some sort of a 'progress' instruction.
86985                                  *
86986                                  *  XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies?
86987                                  */
86988                                 duk_int32_t atom_code_length;
86989                                 duk_uint32_t atom_copies;
86990                                 duk_uint32_t tmp_qmin, tmp_qmax;
86991
86992                                 /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */
86993                                 atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ?
86994                                               re_ctx->curr_token.qmin : re_ctx->curr_token.qmax;
86995                                 if (atom_copies > DUK_RE_MAX_ATOM_COPIES) {
86996                                         DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES);
86997                                         DUK_WO_NORETURN(return;);
86998                                 }
86999
87000                                 /* wipe the capture range made by the atom (if any) */
87001                                 DUK_ASSERT(atom_start_captures <= re_ctx->captures);
87002                                 if (atom_start_captures != re_ctx->captures) {
87003                                         DUK_ASSERT(atom_start_captures < re_ctx->captures);
87004                                         DUK_DDD(DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%ld,%ld]",
87005                                                              (long) atom_start_captures, (long) re_ctx->captures));
87006
87007                                         /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
87008                                         duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (re_ctx->captures - atom_start_captures) * 2U);
87009                                         duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, (atom_start_captures + 1) * 2);
87010                                         duk__insert_u32(re_ctx, (duk_uint32_t) atom_start_offset, DUK_REOP_WIPERANGE);
87011                                 } else {
87012                                         DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld",
87013                                                              (long) atom_start_captures));
87014                                 }
87015
87016                                 atom_code_length = (duk_int32_t) DUK__RE_BUFLEN(re_ctx) - atom_start_offset;
87017
87018                                 /* insert the required matches (qmin) by copying the atom */
87019                                 tmp_qmin = re_ctx->curr_token.qmin;
87020                                 tmp_qmax = re_ctx->curr_token.qmax;
87021                                 while (tmp_qmin > 0) {
87022                                         duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
87023                                         tmp_qmin--;
87024                                         if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
87025                                                 tmp_qmax--;
87026                                         }
87027                                 }
87028                                 DUK_ASSERT(tmp_qmin == 0);
87029
87030                                 /* insert code for matching the remainder - infinite or finite */
87031                                 if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) {
87032                                         /* reuse last emitted atom for remaining 'infinite' quantifier */
87033
87034                                         if (re_ctx->curr_token.qmin == 0) {
87035                                                 /* Special case: original qmin was zero so there is nothing
87036                                                  * to repeat.  Emit an atom copy but jump over it here.
87037                                                  */
87038                                                 duk__append_reop(re_ctx, DUK_REOP_JUMP);
87039                                                 duk__append_jump_offset(re_ctx, atom_code_length);
87040                                                 duk__append_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
87041                                         }
87042                                         if (re_ctx->curr_token.greedy) {
87043                                                 duk__append_reop(re_ctx, DUK_REOP_SPLIT2);   /* prefer jump */
87044                                         } else {
87045                                                 duk__append_reop(re_ctx, DUK_REOP_SPLIT1);   /* prefer direct */
87046                                         }
87047                                         duk__append_jump_offset(re_ctx, -atom_code_length - 1);  /* -1 for opcode */
87048                                 } else {
87049                                         /*
87050                                          *  The remaining matches are emitted as sequence of SPLITs and atom
87051                                          *  copies; the SPLITs skip the remaining copies and match the sequel.
87052                                          *  This sequence needs to be emitted starting from the last copy
87053                                          *  because the SPLITs are variable length due to the variable length
87054                                          *  skip offset.  This causes a lot of memory copying now.
87055                                          *
87056                                          *  Example structure (greedy, match maximum # atoms):
87057                                          *
87058                                          *      SPLIT1 LSEQ
87059                                          *      (atom)
87060                                          *      SPLIT1 LSEQ    ; <- the byte length of this instruction is needed
87061                                          *      (atom)         ; to encode the above SPLIT1 correctly
87062                                          *      ...
87063                                          *   LSEQ:
87064                                          */
87065                                         duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
87066                                         while (tmp_qmax > 0) {
87067                                                 duk__insert_slice(re_ctx, offset, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
87068                                                 if (re_ctx->curr_token.greedy) {
87069                                                         duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1);   /* prefer direct */
87070                                                 } else {
87071                                                         duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2);   /* prefer jump */
87072                                                 }
87073                                                 duk__insert_jump_offset(re_ctx,
87074                                                                         offset + 1,   /* +1 for opcode */
87075                                                                         (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
87076                                                 tmp_qmax--;
87077                                         }
87078                                 }
87079
87080                                 /* remove the original 'template' atom */
87081                                 duk__remove_slice(re_ctx, (duk_uint32_t) atom_start_offset, (duk_uint32_t) atom_code_length);
87082                         }
87083
87084                         /* 'taint' result as complex */
87085                         res_charlen = -1;
87086                         break;
87087                 }
87088                 case DUK_RETOK_ASSERT_START: {
87089                         duk__append_reop(re_ctx, DUK_REOP_ASSERT_START);
87090                         break;
87091                 }
87092                 case DUK_RETOK_ASSERT_END: {
87093                         duk__append_reop(re_ctx, DUK_REOP_ASSERT_END);
87094                         break;
87095                 }
87096                 case DUK_RETOK_ASSERT_WORD_BOUNDARY: {
87097                         duk__append_reop(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
87098                         break;
87099                 }
87100                 case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: {
87101                         duk__append_reop(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
87102                         break;
87103                 }
87104                 case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD:
87105                 case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: {
87106                         duk_uint32_t offset;
87107                         duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ?
87108                                               DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG;
87109
87110                         offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
87111                         duk__parse_disjunction(re_ctx, 0, &tmp_disj);
87112                         duk__append_reop(re_ctx, DUK_REOP_MATCH);
87113
87114                         (void) duk__insert_u32(re_ctx, offset, opcode);
87115                         (void) duk__insert_jump_offset(re_ctx,
87116                                                        offset + 1,   /* +1 for opcode */
87117                                                        (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
87118
87119                         /* 'taint' result as complex -- this is conservative,
87120                          * as lookaheads do not backtrack.
87121                          */
87122                         res_charlen = -1;
87123                         break;
87124                 }
87125                 case DUK_RETOK_ATOM_PERIOD: {
87126                         new_atom_char_length = 1;
87127                         new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
87128                         duk__append_reop(re_ctx, DUK_REOP_PERIOD);
87129                         break;
87130                 }
87131                 case DUK_RETOK_ATOM_CHAR: {
87132                         /* Note: successive characters could be joined into string matches
87133                          * but this is not trivial (consider e.g. '/xyz+/); see docs for
87134                          * more discussion.
87135                          *
87136                          * No support for \u{H+} yet.  While only BMP Unicode escapes are
87137                          * supported for RegExps at present, 'ch' may still be a non-BMP
87138                          * codepoint if it is decoded straight from source text UTF-8.
87139                          * There's no non-BMP support yet so this is handled simply by
87140                          * matching the non-BMP character (which is custom behavior).
87141                          */
87142                         duk_uint32_t ch;
87143
87144                         new_atom_char_length = 1;
87145                         new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
87146                         duk__append_reop(re_ctx, DUK_REOP_CHAR);
87147                         ch = re_ctx->curr_token.num;
87148                         if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
87149                                 ch = (duk_uint32_t) duk_unicode_re_canonicalize_char(re_ctx->thr, (duk_codepoint_t) ch);
87150                         }
87151                         duk__append_u32(re_ctx, ch);
87152                         break;
87153                 }
87154                 case DUK_RETOK_ATOM_DIGIT:
87155                 case DUK_RETOK_ATOM_NOT_DIGIT:
87156                 case DUK_RETOK_ATOM_WHITE:
87157                 case DUK_RETOK_ATOM_NOT_WHITE:
87158                 case DUK_RETOK_ATOM_WORD_CHAR:
87159                 case DUK_RETOK_ATOM_NOT_WORD_CHAR: {
87160                         duk_small_uint_t re_op;
87161                         duk_small_uint_t idx;
87162
87163                         new_atom_char_length = 1;
87164                         new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
87165
87166                         DUK_ASSERT((DUK_RETOK_ATOM_DIGIT & 0x01) != 0);
87167                         DUK_ASSERT((DUK_RETOK_ATOM_WHITE & 0x01) != 0);
87168                         DUK_ASSERT((DUK_RETOK_ATOM_WORD_CHAR & 0x01) != 0);
87169                         DUK_ASSERT((DUK_RETOK_ATOM_NOT_DIGIT & 0x01) == 0);
87170                         DUK_ASSERT((DUK_RETOK_ATOM_NOT_WHITE & 0x01) == 0);
87171                         DUK_ASSERT((DUK_RETOK_ATOM_NOT_WORD_CHAR & 0x01) == 0);
87172                         re_op = (re_ctx->curr_token.t & 0x01) ? DUK_REOP_RANGES : DUK_REOP_INVRANGES;
87173
87174                         DUK_ASSERT(DUK_RETOK_ATOM_WHITE == DUK_RETOK_ATOM_DIGIT + 2);
87175                         DUK_ASSERT(DUK_RETOK_ATOM_WORD_CHAR == DUK_RETOK_ATOM_DIGIT + 4);
87176                         idx = (duk_small_uint_t) ((re_ctx->curr_token.t - DUK_RETOK_ATOM_DIGIT) >> 1U);
87177                         DUK_ASSERT(idx <= 2U);  /* Assume continuous token numbers; also checks negative underflow. */
87178
87179                         duk__append_range_atom_matcher(re_ctx, re_op, duk__re_range_lookup1[idx], duk__re_range_lookup2[idx]);
87180                         break;
87181                 }
87182                 case DUK_RETOK_ATOM_BACKREFERENCE: {
87183                         duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num;
87184                         if (backref > re_ctx->highest_backref) {
87185                                 re_ctx->highest_backref = backref;
87186                         }
87187                         new_atom_char_length = -1;   /* mark as complex */
87188                         new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
87189                         duk__append_reop(re_ctx, DUK_REOP_BACKREFERENCE);
87190                         duk__append_u32(re_ctx, backref);
87191                         break;
87192                 }
87193                 case DUK_RETOK_ATOM_START_CAPTURE_GROUP: {
87194                         duk_uint32_t cap;
87195
87196                         new_atom_char_length = -1;   /* mark as complex (capture handling) */
87197                         new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
87198                         cap = ++re_ctx->captures;
87199                         duk__append_reop(re_ctx, DUK_REOP_SAVE);
87200                         duk__append_u32(re_ctx, cap * 2);
87201                         duk__parse_disjunction(re_ctx, 0, &tmp_disj);  /* retval (sub-atom char length) unused, tainted as complex above */
87202                         duk__append_reop(re_ctx, DUK_REOP_SAVE);
87203                         duk__append_u32(re_ctx, cap * 2 + 1);
87204                         break;
87205                 }
87206                 case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: {
87207                         new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
87208                         duk__parse_disjunction(re_ctx, 0, &tmp_disj);
87209                         new_atom_char_length = tmp_disj.charlen;
87210                         break;
87211                 }
87212                 case DUK_RETOK_ATOM_START_CHARCLASS:
87213                 case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: {
87214                         /*
87215                          *  Range parsing is done with a special lexer function which calls
87216                          *  us for every range parsed.  This is different from how rest of
87217                          *  the parsing works, but avoids a heavy, arbitrary size intermediate
87218                          *  value type to hold the ranges.
87219                          *
87220                          *  Another complication is the handling of character ranges when
87221                          *  case insensitive matching is used (see docs for discussion).
87222                          *  The range handler callback given to the lexer takes care of this
87223                          *  as well.
87224                          *
87225                          *  Note that duplicate ranges are not eliminated when parsing character
87226                          *  classes, so that canonicalization of
87227                          *
87228                          *    [0-9a-fA-Fx-{]
87229                          *
87230                          *  creates the result (note the duplicate ranges):
87231                          *
87232                          *    [0-9A-FA-FX-Z{-{]
87233                          *
87234                          *  where [x-{] is split as a result of canonicalization.  The duplicate
87235                          *  ranges are not a semantics issue: they work correctly.
87236                          */
87237
87238                         duk_uint32_t offset;
87239
87240                         DUK_DD(DUK_DDPRINT("character class"));
87241
87242                         /* insert ranges instruction, range count patched in later */
87243                         new_atom_char_length = 1;
87244                         new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
87245                         duk__append_reop(re_ctx,
87246                                          (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
87247                                          DUK_REOP_RANGES : DUK_REOP_INVRANGES);
87248                         offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);    /* patch in range count later */
87249
87250                         /* parse ranges until character class ends */
87251                         re_ctx->nranges = 0;    /* note: ctx-wide temporary */
87252                         duk_lexer_parse_re_ranges(&re_ctx->lex, duk__regexp_generate_ranges, (void *) re_ctx);
87253
87254                         /* insert range count */
87255                         duk__insert_u32(re_ctx, offset, re_ctx->nranges);
87256                         break;
87257                 }
87258                 case DUK_RETOK_ATOM_END_GROUP: {
87259                         if (expect_eof) {
87260                                 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN);
87261                                 DUK_WO_NORETURN(return;);
87262                         }
87263                         goto done;
87264                 }
87265                 case DUK_RETOK_EOF: {
87266                         if (!expect_eof) {
87267                                 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN);
87268                                 DUK_WO_NORETURN(return;);
87269                         }
87270                         goto done;
87271                 }
87272                 default: {
87273                         DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN);
87274                         DUK_WO_NORETURN(return;);
87275                 }
87276                 }
87277
87278                 /* a complex (new) atom taints the result */
87279                 if (new_atom_start_offset >= 0) {
87280                         if (new_atom_char_length < 0) {
87281                                 res_charlen = -1;
87282                         } else if (res_charlen >= 0) {
87283                                 /* only advance if not tainted */
87284                                 res_charlen += new_atom_char_length;
87285                         }
87286                 }
87287
87288                 /* record previous atom info in case next token is a quantifier */
87289                 atom_start_offset = new_atom_start_offset;
87290                 atom_char_length = new_atom_char_length;
87291                 atom_start_captures = new_atom_start_captures;
87292         }
87293
87294  done:
87295
87296         /* finish up pending jump and split for last alternative */
87297         if (unpatched_disjunction_jump >= 0) {
87298                 duk_uint32_t offset;
87299
87300                 DUK_ASSERT(unpatched_disjunction_split >= 0);
87301                 offset = (duk_uint32_t) unpatched_disjunction_jump;
87302                 offset += duk__insert_jump_offset(re_ctx,
87303                                                   offset,
87304                                                   (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
87305                 /* offset is now target of the pending split (right after jump) */
87306                 duk__insert_jump_offset(re_ctx,
87307                                         (duk_uint32_t) unpatched_disjunction_split,
87308                                         (duk_int32_t) offset - unpatched_disjunction_split);
87309         }
87310
87311 #if 0
87312         out_atom_info->end_captures = re_ctx->captures;
87313 #endif
87314         out_atom_info->charlen = res_charlen;
87315         DUK_DDD(DUK_DDDPRINT("parse disjunction finished: charlen=%ld",
87316                              (long) out_atom_info->charlen));
87317
87318         re_ctx->recursion_depth--;
87319 }
87320
87321 /*
87322  *  Flags parsing (see E5 Section 15.10.4.1).
87323  */
87324
87325 DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) {
87326         const duk_uint8_t *p;
87327         const duk_uint8_t *p_end;
87328         duk_uint32_t flags = 0;
87329
87330         p = DUK_HSTRING_GET_DATA(h);
87331         p_end = p + DUK_HSTRING_GET_BYTELEN(h);
87332
87333         /* Note: can be safely scanned as bytes (undecoded) */
87334
87335         while (p < p_end) {
87336                 duk_uint8_t c = *p++;
87337                 switch (c) {
87338                 case (duk_uint8_t) 'g': {
87339                         if (flags & DUK_RE_FLAG_GLOBAL) {
87340                                 goto flags_error;
87341                         }
87342                         flags |= DUK_RE_FLAG_GLOBAL;
87343                         break;
87344                 }
87345                 case (duk_uint8_t) 'i': {
87346                         if (flags & DUK_RE_FLAG_IGNORE_CASE) {
87347                                 goto flags_error;
87348                         }
87349                         flags |= DUK_RE_FLAG_IGNORE_CASE;
87350                         break;
87351                 }
87352                 case (duk_uint8_t) 'm': {
87353                         if (flags & DUK_RE_FLAG_MULTILINE) {
87354                                 goto flags_error;
87355                         }
87356                         flags |= DUK_RE_FLAG_MULTILINE;
87357                         break;
87358                 }
87359                 default: {
87360                         goto flags_error;
87361                 }
87362                 }
87363         }
87364
87365         return flags;
87366
87367  flags_error:
87368         DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS);
87369         DUK_WO_NORETURN(return 0U;);
87370 }
87371
87372 /*
87373  *  Create escaped RegExp source (E5 Section 15.10.3).
87374  *
87375  *  The current approach is to special case the empty RegExp
87376  *  ('' -> '(?:)') and otherwise replace unescaped '/' characters
87377  *  with '\/' regardless of where they occur in the regexp.
87378  *
87379  *  Note that normalization does not seem to be necessary for
87380  *  RegExp literals (e.g. '/foo/') because to be acceptable as
87381  *  a RegExp literal, the text between forward slashes must
87382  *  already match the escaping requirements (e.g. must not contain
87383  *  unescaped forward slashes or be empty).  Escaping IS needed
87384  *  for expressions like 'new Regexp("...", "")' however.
87385  *  Currently, we re-escape in either case.
87386  *
87387  *  Also note that we process the source here in UTF-8 encoded
87388  *  form.  This is correct, because any non-ASCII characters are
87389  *  passed through without change.
87390  */
87391
87392 DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
87393         duk_hstring *h;
87394         const duk_uint8_t *p;
87395         duk_bufwriter_ctx bw_alloc;
87396         duk_bufwriter_ctx *bw;
87397         duk_uint8_t *q;
87398         duk_size_t i, n;
87399         duk_uint_fast8_t c_prev, c;
87400
87401         h = duk_known_hstring(thr, idx_pattern);
87402         p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
87403         n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
87404
87405         if (n == 0) {
87406                 duk_push_literal(thr, "(?:)");
87407                 return;
87408         }
87409
87410         bw = &bw_alloc;
87411         DUK_BW_INIT_PUSHBUF(thr, bw, n);
87412         q = DUK_BW_GET_PTR(thr, bw);
87413
87414         c_prev = (duk_uint_fast8_t) 0;
87415
87416         for (i = 0; i < n; i++) {
87417                 c = p[i];
87418
87419                 q = DUK_BW_ENSURE_RAW(thr, bw, 2, q);
87420
87421                 if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') {
87422                         /* Unescaped '/' ANYWHERE in the regexp (in disjunction,
87423                          * inside a character class, ...) => same escape works.
87424                          */
87425                         *q++ = DUK_ASC_BACKSLASH;
87426                 }
87427                 *q++ = (duk_uint8_t) c;
87428
87429                 c_prev = c;
87430         }
87431
87432         DUK_BW_SETPTR_AND_COMPACT(thr, bw, q);
87433         (void) duk_buffer_to_string(thr, -1);  /* Safe if input is safe. */
87434
87435         /* [ ... escaped_source ] */
87436 }
87437
87438 /*
87439  *  Exposed regexp compilation primitive.
87440  *
87441  *  Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the
87442  *  actual parsing.  Handles generation of the compiled regexp header and the
87443  *  "boilerplate" capture of the matching substring (save 0 and 1).  Also does some
87444  *  global level regexp checks after recursive compilation has finished.
87445  *
87446  *  An escaped version of the regexp source, suitable for use as a RegExp instance
87447  *  'source' property (see E5 Section 15.10.3), is also left on the stack.
87448  *
87449  *  Input stack:  [ pattern flags ]
87450  *  Output stack: [ bytecode escaped_source ]  (both as strings)
87451  */
87452
87453 DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
87454         duk_re_compiler_ctx re_ctx;
87455         duk_lexer_point lex_point;
87456         duk_hstring *h_pattern;
87457         duk_hstring *h_flags;
87458         duk__re_disjunction_info ign_disj;
87459
87460         DUK_ASSERT(thr != NULL);
87461
87462         /*
87463          *  Args validation
87464          */
87465
87466         /* TypeError if fails */
87467         h_pattern = duk_require_hstring_notsymbol(thr, -2);
87468         h_flags = duk_require_hstring_notsymbol(thr, -1);
87469
87470         /*
87471          *  Create normalized 'source' property (E5 Section 15.10.3).
87472          */
87473
87474         /* [ ... pattern flags ] */
87475
87476         duk__create_escaped_source(thr, -2);
87477
87478         /* [ ... pattern flags escaped_source ] */
87479
87480         /*
87481          *  Init compilation context
87482          */
87483
87484         /* [ ... pattern flags escaped_source buffer ] */
87485
87486         duk_memzero(&re_ctx, sizeof(re_ctx));
87487         DUK_LEXER_INITCTX(&re_ctx.lex);  /* duplicate zeroing, expect for (possible) NULL inits */
87488         re_ctx.thr = thr;
87489         re_ctx.lex.thr = thr;
87490         re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern);
87491         re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern);
87492         re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT;
87493         re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT;
87494         re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags);
87495
87496         DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE);
87497
87498         DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld",
87499                            (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit));
87500
87501         /*
87502          *  Init lexer
87503          */
87504
87505         lex_point.offset = 0;  /* expensive init, just want to fill window */
87506         lex_point.line = 1;
87507         DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point);
87508
87509         /*
87510          *  Compilation
87511          */
87512
87513         DUK_DD(DUK_DDPRINT("starting regexp compilation"));
87514
87515         duk__append_reop(&re_ctx, DUK_REOP_SAVE);
87516         duk__append_7bit(&re_ctx, 0);
87517         duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
87518         duk__append_reop(&re_ctx, DUK_REOP_SAVE);
87519         duk__append_7bit(&re_ctx, 1);
87520         duk__append_reop(&re_ctx, DUK_REOP_MATCH);
87521
87522         /*
87523          *  Check for invalid backreferences; note that it is NOT an error
87524          *  to back-reference a capture group which has not yet been introduced
87525          *  in the pattern (as in /\1(foo)/); in fact, the backreference will
87526          *  always match!  It IS an error to back-reference a capture group
87527          *  which will never be introduced in the pattern.  Thus, we can check
87528          *  for such references only after parsing is complete.
87529          */
87530
87531         if (re_ctx.highest_backref > re_ctx.captures) {
87532                 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS);
87533                 DUK_WO_NORETURN(return;);
87534         }
87535
87536         /*
87537          *  Emit compiled regexp header: flags, ncaptures
87538          *  (insertion order inverted on purpose)
87539          */
87540
87541         duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2);
87542         duk__insert_u32(&re_ctx, 0, re_ctx.re_flags);
87543
87544         /* [ ... pattern flags escaped_source buffer ] */
87545
87546         DUK_BW_COMPACT(thr, &re_ctx.bw);
87547         (void) duk_buffer_to_string(thr, -1);  /* Safe because flags is at most 7 bit. */
87548
87549         /* [ ... pattern flags escaped_source bytecode ] */
87550
87551         /*
87552          *  Finalize stack
87553          */
87554
87555         duk_remove(thr, -4);     /* -> [ ... flags escaped_source bytecode ] */
87556         duk_remove(thr, -3);     /* -> [ ... escaped_source bytecode ] */
87557
87558         DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
87559                            (duk_tval *) duk_get_tval(thr, -1), (duk_tval *) duk_get_tval(thr, -2)));
87560 }
87561
87562 /*
87563  *  Create a RegExp instance (E5 Section 15.10.7).
87564  *
87565  *  Note: the output stack left by duk_regexp_compile() is directly compatible
87566  *  with the input here.
87567  *
87568  *  Input stack:  [ escaped_source bytecode ]  (both as strings)
87569  *  Output stack: [ RegExp ]
87570  */
87571
87572 DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
87573         duk_hobject *h;
87574
87575         /* [ ... escaped_source bytecode ] */
87576
87577         duk_push_object(thr);
87578         h = duk_known_hobject(thr, -1);
87579         duk_insert(thr, -3);
87580
87581         /* [ ... regexp_object escaped_source bytecode ] */
87582
87583         DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
87584         DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
87585
87586         duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
87587
87588         /* [ ... regexp_object escaped_source ] */
87589
87590         /* In ES2015 .source, and the .global, .multiline, etc flags are
87591          * inherited getters.  Store the escaped source as an internal
87592          * property for the getter.
87593          */
87594
87595         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
87596
87597         /* [ ... regexp_object ] */
87598
87599         duk_push_int(thr, 0);
87600         duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
87601
87602         /* [ ... regexp_object ] */
87603 }
87604
87605 #else  /* DUK_USE_REGEXP_SUPPORT */
87606
87607 /* regexp support disabled */
87608
87609 #endif  /* DUK_USE_REGEXP_SUPPORT */
87610
87611 /* automatic undefs */
87612 #undef DUK__RE_BUFLEN
87613 #undef DUK__RE_INITIAL_BUFSIZE
87614 #line 1 "duk_regexp_executor.c"
87615 /*
87616  *  Regexp executor.
87617  *
87618  *  Safety: the ECMAScript executor should prevent user from reading and
87619  *  replacing regexp bytecode.  Even so, the executor must validate all
87620  *  memory accesses etc.  When an invalid access is detected (e.g. a 'save'
87621  *  opcode to invalid, unallocated index) it should fail with an internal
87622  *  error but not cause a segmentation fault.
87623  *
87624  *  Notes:
87625  *
87626  *    - Backtrack counts are limited to unsigned 32 bits but should
87627  *      technically be duk_size_t for strings longer than 4G chars.
87628  *      This also requires a regexp bytecode change.
87629  */
87630
87631 /* #include duk_internal.h -> already included */
87632
87633 #if defined(DUK_USE_REGEXP_SUPPORT)
87634
87635 /*
87636  *  Helpers for UTF-8 handling
87637  *
87638  *  For bytecode readers the duk_uint32_t and duk_int32_t types are correct
87639  *  because they're used for more than just codepoints.
87640  */
87641
87642 DUK_LOCAL duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
87643         return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
87644 }
87645
87646 DUK_LOCAL duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
87647         duk_uint32_t t;
87648
87649         /* signed integer encoding needed to work with UTF-8 */
87650         t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
87651         if (t & 1) {
87652                 return -((duk_int32_t) (t >> 1));
87653         } else {
87654                 return (duk_int32_t) (t >> 1);
87655         }
87656 }
87657
87658 DUK_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) {
87659         const duk_uint8_t *p;
87660
87661         /* Note: allow backtracking from p == ptr_end */
87662         p = *ptr;
87663         if (p < ptr_start || p > ptr_end) {
87664                 goto fail;
87665         }
87666
87667         while (count > 0) {
87668                 for (;;) {
87669                         p--;
87670                         if (p < ptr_start) {
87671                                 goto fail;
87672                         }
87673                         if ((*p & 0xc0) != 0x80) {
87674                                 /* utf-8 continuation bytes have the form 10xx xxxx */
87675                                 break;
87676                         }
87677                 }
87678                 count--;
87679         }
87680         *ptr = p;
87681         return p;
87682
87683  fail:
87684         DUK_ERROR_INTERNAL(thr);
87685         DUK_WO_NORETURN(return NULL;);
87686 }
87687
87688 DUK_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) {
87689         const duk_uint8_t *p;
87690
87691         p = *ptr;
87692         if (p < ptr_start || p >= ptr_end) {
87693                 goto fail;
87694         }
87695
87696         while (count > 0) {
87697                 for (;;) {
87698                         p++;
87699
87700                         /* Note: if encoding ends by hitting end of input, we don't check that
87701                          * the encoding is valid, we just assume it is.
87702                          */
87703                         if (p >= ptr_end || ((*p & 0xc0) != 0x80)) {
87704                                 /* utf-8 continuation bytes have the form 10xx xxxx */
87705                                 break;
87706                         }
87707                 }
87708                 count--;
87709         }
87710
87711         *ptr = p;
87712         return p;
87713
87714  fail:
87715         DUK_ERROR_INTERNAL(thr);
87716         DUK_WO_NORETURN(return NULL;);
87717 }
87718
87719 /*
87720  *  Helpers for dealing with the input string
87721  */
87722
87723 /* Get a (possibly canonicalized) input character from current sp.  The input
87724  * itself is never modified, and captures always record non-canonicalized
87725  * characters even in case-insensitive matching.  Return <0 if out of input.
87726  */
87727 DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) {
87728         duk_codepoint_t res;
87729
87730         if (*sp >= re_ctx->input_end) {
87731                 return -1;
87732         }
87733         res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
87734         if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
87735                 res = duk_unicode_re_canonicalize_char(re_ctx->thr, res);
87736         }
87737         return res;
87738 }
87739
87740 DUK_LOCAL const duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp, duk_uint_fast32_t count) {
87741         return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count);
87742 }
87743
87744 /* Backtrack utf-8 input and return a (possibly canonicalized) input character. */
87745 DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *sp) {
87746         /* note: caller 'sp' is intentionally not updated here */
87747         (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1);
87748         return duk__inp_get_cp(re_ctx, &sp);
87749 }
87750
87751 /*
87752  *  Regexp recursive matching function.
87753  *
87754  *  Returns 'sp' on successful match (points to character after last matched one),
87755  *  NULL otherwise.
87756  *
87757  *  The C recursion depth limit check is only performed in this function, this
87758  *  suffices because the function is present in all true recursion required by
87759  *  regexp execution.
87760  */
87761
87762 DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) {
87763         if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
87764                 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT);
87765                 DUK_WO_NORETURN(return NULL;);
87766         }
87767         re_ctx->recursion_depth++;
87768
87769         for (;;) {
87770                 duk_small_int_t op;
87771
87772                 if (re_ctx->steps_count >= re_ctx->steps_limit) {
87773                         DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT);
87774                         DUK_WO_NORETURN(return NULL;);
87775                 }
87776                 re_ctx->steps_count++;
87777
87778                 /* Opcodes are at most 7 bits now so they encode to one byte.  If this
87779                  * were not the case or 'pc' is invalid here (due to a bug etc) we'll
87780                  * still fail safely through the switch default case.
87781                  */
87782                 DUK_ASSERT(pc[0] <= 0x7fU);
87783 #if 0
87784                 op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc);
87785 #endif
87786                 op = *pc++;
87787
87788                 DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld",
87789                                      (long) re_ctx->recursion_depth,
87790                                      (long) re_ctx->steps_count,
87791                                      (long) (pc - re_ctx->bytecode),
87792                                      (long) (sp - re_ctx->input),
87793                                      (long) op));
87794
87795                 switch (op) {
87796                 case DUK_REOP_MATCH: {
87797                         goto match;
87798                 }
87799                 case DUK_REOP_CHAR: {
87800                         /*
87801                          *  Byte-based matching would be possible for case-sensitive
87802                          *  matching but not for case-insensitive matching.  So, we
87803                          *  match by decoding the input and bytecode character normally.
87804                          *
87805                          *  Bytecode characters are assumed to be already canonicalized.
87806                          *  Input characters are canonicalized automatically by
87807                          *  duk__inp_get_cp() if necessary.
87808                          *
87809                          *  There is no opcode for matching multiple characters.  The
87810                          *  regexp compiler has trouble joining strings efficiently
87811                          *  during compilation.  See doc/regexp.rst for more discussion.
87812                          */
87813                         duk_codepoint_t c1, c2;
87814
87815                         c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
87816                         DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) ||
87817                                    c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1));  /* canonicalized by compiler */
87818                         c2 = duk__inp_get_cp(re_ctx, &sp);
87819                         /* No need to check for c2 < 0 (end of input): because c1 >= 0, it
87820                          * will fail the match below automatically and cause goto fail.
87821                          */
87822 #if 0
87823                         if (c2 < 0) {
87824                                 goto fail;
87825                         }
87826 #endif
87827                         DUK_ASSERT(c1 >= 0);
87828
87829                         DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld", (long) c1, (long) c2));
87830                         if (c1 != c2) {
87831                                 goto fail;
87832                         }
87833                         break;
87834                 }
87835                 case DUK_REOP_PERIOD: {
87836                         duk_codepoint_t c;
87837
87838                         c = duk__inp_get_cp(re_ctx, &sp);
87839                         if (c < 0 || duk_unicode_is_line_terminator(c)) {
87840                                 /* E5 Sections 15.10.2.8, 7.3 */
87841                                 goto fail;
87842                         }
87843                         break;
87844                 }
87845                 case DUK_REOP_RANGES:
87846                 case DUK_REOP_INVRANGES: {
87847                         duk_uint32_t n;
87848                         duk_codepoint_t c;
87849                         duk_small_int_t match;
87850
87851                         n = duk__bc_get_u32(re_ctx, &pc);
87852                         c = duk__inp_get_cp(re_ctx, &sp);
87853                         if (c < 0) {
87854                                 goto fail;
87855                         }
87856
87857                         match = 0;
87858                         while (n) {
87859                                 duk_codepoint_t r1, r2;
87860                                 r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
87861                                 r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
87862                                 DUK_DDD(DUK_DDDPRINT("matching ranges/invranges, n=%ld, r1=%ld, r2=%ld, c=%ld",
87863                                                      (long) n, (long) r1, (long) r2, (long) c));
87864                                 if (c >= r1 && c <= r2) {
87865                                         /* Note: don't bail out early, we must read all the ranges from
87866                                          * bytecode.  Another option is to skip them efficiently after
87867                                          * breaking out of here.  Prefer smallest code.
87868                                          */
87869                                         match = 1;
87870                                 }
87871                                 n--;
87872                         }
87873
87874                         if (op == DUK_REOP_RANGES) {
87875                                 if (!match) {
87876                                         goto fail;
87877                                 }
87878                         } else {
87879                                 DUK_ASSERT(op == DUK_REOP_INVRANGES);
87880                                 if (match) {
87881                                         goto fail;
87882                                 }
87883                         }
87884                         break;
87885                 }
87886                 case DUK_REOP_ASSERT_START: {
87887                         duk_codepoint_t c;
87888
87889                         if (sp <= re_ctx->input) {
87890                                 break;
87891                         }
87892                         if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
87893                                 goto fail;
87894                         }
87895                         c = duk__inp_get_prev_cp(re_ctx, sp);
87896                         if (duk_unicode_is_line_terminator(c)) {
87897                                 /* E5 Sections 15.10.2.8, 7.3 */
87898                                 break;
87899                         }
87900                         goto fail;
87901                 }
87902                 case DUK_REOP_ASSERT_END: {
87903                         duk_codepoint_t c;
87904                         const duk_uint8_t *tmp_sp;
87905
87906                         tmp_sp = sp;
87907                         c = duk__inp_get_cp(re_ctx, &tmp_sp);
87908                         if (c < 0) {
87909                                 break;
87910                         }
87911                         if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
87912                                 goto fail;
87913                         }
87914                         if (duk_unicode_is_line_terminator(c)) {
87915                                 /* E5 Sections 15.10.2.8, 7.3 */
87916                                 break;
87917                         }
87918                         goto fail;
87919                 }
87920                 case DUK_REOP_ASSERT_WORD_BOUNDARY:
87921                 case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: {
87922                         /*
87923                          *  E5 Section 15.10.2.6.  The previous and current character
87924                          *  should -not- be canonicalized as they are now.  However,
87925                          *  canonicalization does not affect the result of IsWordChar()
87926                          *  (which depends on Unicode characters never canonicalizing
87927                          *  into ASCII characters) so this does not matter.
87928                          */
87929                         duk_small_int_t w1, w2;
87930
87931                         if (sp <= re_ctx->input) {
87932                                 w1 = 0;  /* not a wordchar */
87933                         } else {
87934                                 duk_codepoint_t c;
87935                                 c = duk__inp_get_prev_cp(re_ctx, sp);
87936                                 w1 = duk_unicode_re_is_wordchar(c);
87937                         }
87938                         if (sp >= re_ctx->input_end) {
87939                                 w2 = 0;  /* not a wordchar */
87940                         } else {
87941                                 const duk_uint8_t *tmp_sp = sp;  /* dummy so sp won't get updated */
87942                                 duk_codepoint_t c;
87943                                 c = duk__inp_get_cp(re_ctx, &tmp_sp);
87944                                 w2 = duk_unicode_re_is_wordchar(c);
87945                         }
87946
87947                         if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) {
87948                                 if (w1 == w2) {
87949                                         goto fail;
87950                                 }
87951                         } else {
87952                                 DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
87953                                 if (w1 != w2) {
87954                                         goto fail;
87955                                 }
87956                         }
87957                         break;
87958                 }
87959                 case DUK_REOP_JUMP: {
87960                         duk_int32_t skip;
87961
87962                         skip = duk__bc_get_i32(re_ctx, &pc);
87963                         pc += skip;
87964                         break;
87965                 }
87966                 case DUK_REOP_SPLIT1: {
87967                         /* split1: prefer direct execution (no jump) */
87968                         const duk_uint8_t *sub_sp;
87969                         duk_int32_t skip;
87970
87971                         skip = duk__bc_get_i32(re_ctx, &pc);
87972                         sub_sp = duk__match_regexp(re_ctx, pc, sp);
87973                         if (sub_sp) {
87974                                 sp = sub_sp;
87975                                 goto match;
87976                         }
87977                         pc += skip;
87978                         break;
87979                 }
87980                 case DUK_REOP_SPLIT2: {
87981                         /* split2: prefer jump execution (not direct) */
87982                         const duk_uint8_t *sub_sp;
87983                         duk_int32_t skip;
87984
87985                         skip = duk__bc_get_i32(re_ctx, &pc);
87986                         sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
87987                         if (sub_sp) {
87988                                 sp = sub_sp;
87989                                 goto match;
87990                         }
87991                         break;
87992                 }
87993                 case DUK_REOP_SQMINIMAL: {
87994                         duk_uint32_t q, qmin, qmax;
87995                         duk_int32_t skip;
87996                         const duk_uint8_t *sub_sp;
87997
87998                         qmin = duk__bc_get_u32(re_ctx, &pc);
87999                         qmax = duk__bc_get_u32(re_ctx, &pc);
88000                         skip = duk__bc_get_i32(re_ctx, &pc);
88001                         DUK_DDD(DUK_DDDPRINT("minimal quantifier, qmin=%lu, qmax=%lu, skip=%ld",
88002                                              (unsigned long) qmin, (unsigned long) qmax, (long) skip));
88003
88004                         q = 0;
88005                         while (q <= qmax) {
88006                                 if (q >= qmin) {
88007                                         sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
88008                                         if (sub_sp) {
88009                                                 sp = sub_sp;
88010                                                 goto match;
88011                                         }
88012                                 }
88013                                 sub_sp = duk__match_regexp(re_ctx, pc, sp);
88014                                 if (!sub_sp) {
88015                                         break;
88016                                 }
88017                                 sp = sub_sp;
88018                                 q++;
88019                         }
88020                         goto fail;
88021                 }
88022                 case DUK_REOP_SQGREEDY: {
88023                         duk_uint32_t q, qmin, qmax, atomlen;
88024                         duk_int32_t skip;
88025                         const duk_uint8_t *sub_sp;
88026
88027                         qmin = duk__bc_get_u32(re_ctx, &pc);
88028                         qmax = duk__bc_get_u32(re_ctx, &pc);
88029                         atomlen = duk__bc_get_u32(re_ctx, &pc);
88030                         skip = duk__bc_get_i32(re_ctx, &pc);
88031                         DUK_DDD(DUK_DDDPRINT("greedy quantifier, qmin=%lu, qmax=%lu, atomlen=%lu, skip=%ld",
88032                                              (unsigned long) qmin, (unsigned long) qmax, (unsigned long) atomlen, (long) skip));
88033
88034                         q = 0;
88035                         while (q < qmax) {
88036                                 sub_sp = duk__match_regexp(re_ctx, pc, sp);
88037                                 if (!sub_sp) {
88038                                         break;
88039                                 }
88040                                 sp = sub_sp;
88041                                 q++;
88042                         }
88043                         while (q >= qmin) {
88044                                 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
88045                                 if (sub_sp) {
88046                                         sp = sub_sp;
88047                                         goto match;
88048                                 }
88049                                 if (q == qmin) {
88050                                         break;
88051                                 }
88052
88053                                 /* Note: if atom were to contain e.g. captures, we would need to
88054                                  * re-match the atom to get correct captures.  Simply quantifiers
88055                                  * do not allow captures in their atom now, so this is not an issue.
88056                                  */
88057
88058                                 DUK_DDD(DUK_DDDPRINT("greedy quantifier, backtrack %ld characters (atomlen)",
88059                                                      (long) atomlen));
88060                                 sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen);
88061                                 q--;
88062                         }
88063                         goto fail;
88064                 }
88065                 case DUK_REOP_SAVE: {
88066                         duk_uint32_t idx;
88067                         const duk_uint8_t *old;
88068                         const duk_uint8_t *sub_sp;
88069
88070                         idx = duk__bc_get_u32(re_ctx, &pc);
88071                         if (idx >= re_ctx->nsaved) {
88072                                 /* idx is unsigned, < 0 check is not necessary */
88073                                 DUK_D(DUK_DPRINT("internal error, regexp save index insane: idx=%ld", (long) idx));
88074                                 goto internal_error;
88075                         }
88076                         old = re_ctx->saved[idx];
88077                         re_ctx->saved[idx] = sp;
88078                         sub_sp = duk__match_regexp(re_ctx, pc, sp);
88079                         if (sub_sp) {
88080                                 sp = sub_sp;
88081                                 goto match;
88082                         }
88083                         re_ctx->saved[idx] = old;
88084                         goto fail;
88085                 }
88086                 case DUK_REOP_WIPERANGE: {
88087                         /* Wipe capture range and save old values for backtracking.
88088                          *
88089                          * XXX: this typically happens with a relatively small idx_count.
88090                          * It might be useful to handle cases where the count is small
88091                          * (say <= 8) by saving the values in stack instead.  This would
88092                          * reduce memory churn and improve performance, at the cost of a
88093                          * slightly higher code footprint.
88094                          */
88095                         duk_uint32_t idx_start, idx_count;
88096 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
88097                         duk_uint32_t idx_end, idx;
88098 #endif
88099                         duk_uint8_t **range_save;
88100                         const duk_uint8_t *sub_sp;
88101
88102                         idx_start = duk__bc_get_u32(re_ctx, &pc);
88103                         idx_count = duk__bc_get_u32(re_ctx, &pc);
88104                         DUK_DDD(DUK_DDDPRINT("wipe saved range: start=%ld, count=%ld -> [%ld,%ld] (captures [%ld,%ld])",
88105                                              (long) idx_start, (long) idx_count,
88106                                              (long) idx_start, (long) (idx_start + idx_count - 1),
88107                                              (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
88108                         if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) {
88109                                 /* idx is unsigned, < 0 check is not necessary */
88110                                 DUK_D(DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%ld, idx_count=%ld",
88111                                                  (long) idx_start, (long) idx_count));
88112                                 goto internal_error;
88113                         }
88114                         DUK_ASSERT(idx_count > 0);
88115
88116                         duk_require_stack(re_ctx->thr, 1);
88117                         range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr,
88118                                                                                    sizeof(duk_uint8_t *) * idx_count);
88119                         DUK_ASSERT(range_save != NULL);
88120                         duk_memcpy(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
88121 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
88122                         idx_end = idx_start + idx_count;
88123                         for (idx = idx_start; idx < idx_end; idx++) {
88124                                 re_ctx->saved[idx] = NULL;
88125                         }
88126 #else
88127                         duk_memzero((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count);
88128 #endif
88129
88130                         sub_sp = duk__match_regexp(re_ctx, pc, sp);
88131                         if (sub_sp) {
88132                                 /* match: keep wiped/resaved values */
88133                                 DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
88134                                                      (long) idx_start, (long) (idx_start + idx_count - 1),
88135                                                      (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
88136                                 duk_pop_unsafe(re_ctx->thr);
88137                                 sp = sub_sp;
88138                                 goto match;
88139                         }
88140
88141                         /* fail: restore saves */
88142                         DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
88143                                              (long) idx_start, (long) (idx_start + idx_count - 1),
88144                                              (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
88145                         duk_memcpy((void *) (re_ctx->saved + idx_start),
88146                                    (const void *) range_save,
88147                                    sizeof(duk_uint8_t *) * idx_count);
88148                         duk_pop_unsafe(re_ctx->thr);
88149                         goto fail;
88150                 }
88151                 case DUK_REOP_LOOKPOS:
88152                 case DUK_REOP_LOOKNEG: {
88153                         /*
88154                          *  Needs a save of multiple saved[] entries depending on what range
88155                          *  may be overwritten.  Because the regexp parser does no such analysis,
88156                          *  we currently save the entire saved array here.  Lookaheads are thus
88157                          *  a bit expensive.  Note that the saved array is not needed for just
88158                          *  the lookahead sub-match, but for the matching of the entire sequel.
88159                          *
88160                          *  The temporary save buffer is pushed on to the valstack to handle
88161                          *  errors correctly.  Each lookahead causes a C recursion and pushes
88162                          *  more stuff on the value stack.  If the C recursion limit is less
88163                          *  than the value stack slack, there is no need to check the stack.
88164                          *  We do so regardless, just in case.
88165                          */
88166
88167                         duk_int32_t skip;
88168                         duk_uint8_t **full_save;
88169                         const duk_uint8_t *sub_sp;
88170
88171                         DUK_ASSERT(re_ctx->nsaved > 0);
88172
88173                         duk_require_stack(re_ctx->thr, 1);
88174                         full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero(re_ctx->thr,
88175                                                                                   sizeof(duk_uint8_t *) * re_ctx->nsaved);
88176                         DUK_ASSERT(full_save != NULL);
88177                         duk_memcpy(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
88178
88179                         skip = duk__bc_get_i32(re_ctx, &pc);
88180                         sub_sp = duk__match_regexp(re_ctx, pc, sp);
88181                         if (op == DUK_REOP_LOOKPOS) {
88182                                 if (!sub_sp) {
88183                                         goto lookahead_fail;
88184                                 }
88185                         } else {
88186                                 if (sub_sp) {
88187                                         goto lookahead_fail;
88188                                 }
88189                         }
88190                         sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
88191                         if (sub_sp) {
88192                                 /* match: keep saves */
88193                                 duk_pop_unsafe(re_ctx->thr);
88194                                 sp = sub_sp;
88195                                 goto match;
88196                         }
88197
88198                         /* fall through */
88199
88200                  lookahead_fail:
88201                         /* fail: restore saves */
88202                         duk_memcpy((void *) re_ctx->saved,
88203                                    (const void *) full_save,
88204                                    sizeof(duk_uint8_t *) * re_ctx->nsaved);
88205                         duk_pop_unsafe(re_ctx->thr);
88206                         goto fail;
88207                 }
88208                 case DUK_REOP_BACKREFERENCE: {
88209                         /*
88210                          *  Byte matching for back-references would be OK in case-
88211                          *  sensitive matching.  In case-insensitive matching we need
88212                          *  to canonicalize characters, so back-reference matching needs
88213                          *  to be done with codepoints instead.  So, we just decode
88214                          *  everything normally here, too.
88215                          *
88216                          *  Note: back-reference index which is 0 or higher than
88217                          *  NCapturingParens (= number of capturing parens in the
88218                          *  -entire- regexp) is a compile time error.  However, a
88219                          *  backreference referring to a valid capture which has
88220                          *  not matched anything always succeeds!  See E5 Section
88221                          *  15.10.2.9, step 5, sub-step 3.
88222                          */
88223                         duk_uint32_t idx;
88224                         const duk_uint8_t *p;
88225
88226                         idx = duk__bc_get_u32(re_ctx, &pc);
88227                         idx = idx << 1;  /* backref n -> saved indices [n*2, n*2+1] */
88228                         if (idx < 2 || idx + 1 >= re_ctx->nsaved) {
88229                                 /* regexp compiler should catch these */
88230                                 DUK_D(DUK_DPRINT("internal error, backreference index insane"));
88231                                 goto internal_error;
88232                         }
88233                         if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) {
88234                                 /* capture is 'undefined', always matches! */
88235                                 DUK_DDD(DUK_DDDPRINT("backreference: saved[%ld,%ld] not complete, always match",
88236                                                      (long) idx, (long) (idx + 1)));
88237                                 break;
88238                         }
88239                         DUK_DDD(DUK_DDDPRINT("backreference: match saved[%ld,%ld]", (long) idx, (long) (idx + 1)));
88240
88241                         p = re_ctx->saved[idx];
88242                         while (p < re_ctx->saved[idx+1]) {
88243                                 duk_codepoint_t c1, c2;
88244
88245                                 /* Note: not necessary to check p against re_ctx->input_end:
88246                                  * the memory access is checked by duk__inp_get_cp(), while
88247                                  * valid compiled regexps cannot write a saved[] entry
88248                                  * which points to outside the string.
88249                                  */
88250                                 c1 = duk__inp_get_cp(re_ctx, &p);
88251                                 DUK_ASSERT(c1 >= 0);
88252                                 c2 = duk__inp_get_cp(re_ctx, &sp);
88253                                 /* No need for an explicit c2 < 0 check: because c1 >= 0,
88254                                  * the comparison will always fail if c2 < 0.
88255                                  */
88256 #if 0
88257                                 if (c2 < 0) {
88258                                         goto fail;
88259                                 }
88260 #endif
88261                                 if (c1 != c2) {
88262                                         goto fail;
88263                                 }
88264                         }
88265                         break;
88266                 }
88267                 default: {
88268                         DUK_D(DUK_DPRINT("internal error, regexp opcode error: %ld", (long) op));
88269                         goto internal_error;
88270                 }
88271                 }
88272         }
88273
88274  match:
88275         re_ctx->recursion_depth--;
88276         return sp;
88277
88278  fail:
88279         re_ctx->recursion_depth--;
88280         return NULL;
88281
88282  internal_error:
88283         DUK_ERROR_INTERNAL(re_ctx->thr);
88284         DUK_WO_NORETURN(return NULL;);
88285 }
88286
88287 /*
88288  *  Exposed matcher function which provides the semantics of RegExp.prototype.exec().
88289  *
88290  *  RegExp.prototype.test() has the same semantics as exec() but does not return the
88291  *  result object (which contains the matching string and capture groups).  Currently
88292  *  there is no separate test() helper, so a temporary result object is created and
88293  *  discarded if test() is needed.  This is intentional, to save code space.
88294  *
88295  *  Input stack:  [ ... re_obj input ]
88296  *  Output stack: [ ... result ]
88297  */
88298
88299 DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
88300         duk_re_matcher_ctx re_ctx;
88301         duk_hobject *h_regexp;
88302         duk_hstring *h_bytecode;
88303         duk_hstring *h_input;
88304         duk_uint8_t *p_buf;
88305         const duk_uint8_t *pc;
88306         const duk_uint8_t *sp;
88307         duk_small_int_t match = 0;
88308         duk_small_int_t global;
88309         duk_uint_fast32_t i;
88310         double d;
88311         duk_uint32_t char_offset;
88312
88313         DUK_ASSERT(thr != NULL);
88314
88315         DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T",
88316                            (duk_tval *) duk_get_tval(thr, -2),
88317                            (duk_tval *) duk_get_tval(thr, -1)));
88318
88319         /*
88320          *  Regexp instance check, bytecode check, input coercion.
88321          *
88322          *  See E5 Section 15.10.6.
88323          */
88324
88325         /* TypeError if wrong; class check, see E5 Section 15.10.6 */
88326         h_regexp = duk_require_hobject_with_class(thr, -2, DUK_HOBJECT_CLASS_REGEXP);
88327         DUK_ASSERT(h_regexp != NULL);
88328         DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
88329         DUK_UNREF(h_regexp);
88330
88331         h_input = duk_to_hstring(thr, -1);
88332         DUK_ASSERT(h_input != NULL);
88333
88334         duk_get_prop_stridx_short(thr, -2, DUK_STRIDX_INT_BYTECODE);  /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
88335         h_bytecode = duk_require_hstring(thr, -1);  /* no regexp instance should exist without a non-configurable bytecode property */
88336         DUK_ASSERT(h_bytecode != NULL);
88337
88338         /*
88339          *  Basic context initialization.
88340          *
88341          *  Some init values are read from the bytecode header
88342          *  whose format is (UTF-8 codepoints):
88343          *
88344          *    uint   flags
88345          *    uint   nsaved (even, 2n+2 where n = num captures)
88346          */
88347
88348         /* [ ... re_obj input bc ] */
88349
88350         duk_memzero(&re_ctx, sizeof(re_ctx));
88351
88352         re_ctx.thr = thr;
88353         re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
88354         re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input);
88355         re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
88356         re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode);
88357         re_ctx.saved = NULL;
88358         re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT;
88359         re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT;
88360
88361         /* read header */
88362         pc = re_ctx.bytecode;
88363         re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc);
88364         re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc);
88365         re_ctx.bytecode = pc;
88366
88367         DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL);  /* must fit into duk_small_int_t */
88368         global = (duk_small_int_t) (force_global | (duk_small_int_t) (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
88369
88370         DUK_ASSERT(re_ctx.nsaved >= 2);
88371         DUK_ASSERT((re_ctx.nsaved % 2) == 0);
88372
88373         p_buf = (duk_uint8_t *) duk_push_fixed_buffer(thr, sizeof(duk_uint8_t *) * re_ctx.nsaved);  /* rely on zeroing */
88374         DUK_UNREF(p_buf);
88375         re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(thr, -1, NULL);
88376         DUK_ASSERT(re_ctx.saved != NULL);
88377
88378         /* [ ... re_obj input bc saved_buf ] */
88379
88380 #if defined(DUK_USE_EXPLICIT_NULL_INIT)
88381         for (i = 0; i < re_ctx.nsaved; i++) {
88382                 re_ctx.saved[i] = (duk_uint8_t *) NULL;
88383         }
88384 #elif defined(DUK_USE_ZERO_BUFFER_DATA)
88385         /* buffer is automatically zeroed */
88386 #else
88387         duk_memzero((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved);
88388 #endif
88389
88390         DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld",
88391                              (unsigned long) re_ctx.re_flags, (long) re_ctx.nsaved, (long) re_ctx.recursion_limit,
88392                              (long) re_ctx.steps_limit));
88393
88394         /*
88395          *  Get starting character offset for match, and initialize 'sp' based on it.
88396          *
88397          *  Note: lastIndex is non-configurable so it must be present (we check the
88398          *  internal class of the object above, so we know it is).  User code can set
88399          *  its value to an arbitrary (garbage) value though; E5 requires that lastIndex
88400          *  be coerced to a number before using.  The code below works even if the
88401          *  property is missing: the value will then be coerced to zero.
88402          *
88403          *  Note: lastIndex may be outside Uint32 range even after ToInteger() coercion.
88404          *  For instance, ToInteger(+Infinity) = +Infinity.  We track the match offset
88405          *  as an integer, but pre-check it to be inside the 32-bit range before the loop.
88406          *  If not, the check in E5 Section 15.10.6.2, step 9.a applies.
88407          */
88408
88409         /* XXX: lastIndex handling produces a lot of asm */
88410
88411         /* [ ... re_obj input bc saved_buf ] */
88412
88413         duk_get_prop_stridx_short(thr, -4, DUK_STRIDX_LAST_INDEX);  /* -> [ ... re_obj input bc saved_buf lastIndex ] */
88414         (void) duk_to_int(thr, -1);  /* ToInteger(lastIndex) */
88415         d = duk_get_number(thr, -1);  /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
88416         duk_pop_nodecref_unsafe(thr);
88417
88418         if (global) {
88419                 if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
88420                         /* match fail */
88421                         char_offset = 0;   /* not really necessary */
88422                         DUK_ASSERT(match == 0);
88423                         goto match_over;
88424                 }
88425                 char_offset = (duk_uint32_t) d;
88426         } else {
88427                 /* lastIndex must be ignored for non-global regexps, but get the
88428                  * value for (theoretical) side effects.  No side effects can
88429                  * really occur, because lastIndex is a normal property and is
88430                  * always non-configurable for RegExp instances.
88431                  */
88432                 char_offset = (duk_uint32_t) 0;
88433         }
88434
88435         DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
88436         sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset);
88437
88438         /*
88439          *  Match loop.
88440          *
88441          *  Try matching at different offsets until match found or input exhausted.
88442          */
88443
88444         /* [ ... re_obj input bc saved_buf ] */
88445
88446         DUK_ASSERT(match == 0);
88447
88448         for (;;) {
88449                 /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */
88450                 DUK_ASSERT_DISABLE(char_offset >= 0);
88451                 DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
88452
88453                 /* Note: re_ctx.steps is intentionally not reset, it applies to the entire unanchored match */
88454                 DUK_ASSERT(re_ctx.recursion_depth == 0);
88455
88456                 DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
88457                                      (long) char_offset, (const void *) sp,
88458                                      (const void *) re_ctx.input, (const void *) re_ctx.input_end));
88459
88460                 /*
88461                  *  Note:
88462                  *
88463                  *    - duk__match_regexp() is required not to longjmp() in ordinary "non-match"
88464                  *      conditions; a longjmp() will terminate the entire matching process.
88465                  *
88466                  *    - Clearing saved[] is not necessary because backtracking does it
88467                  *
88468                  *    - Backtracking also rewinds re_ctx.recursion back to zero, unless an
88469                  *      internal/limit error occurs (which causes a longjmp())
88470                  *
88471                  *    - If we supported anchored matches, we would break out here
88472                  *      unconditionally; however, ECMAScript regexps don't have anchored
88473                  *      matches.  It might make sense to implement a fast bail-out if
88474                  *      the regexp begins with '^' and sp is not 0: currently we'll just
88475                  *      run through the entire input string, trivially failing the match
88476                  *      at every non-zero offset.
88477                  */
88478
88479                 if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) {
88480                         DUK_DDD(DUK_DDDPRINT("match at offset %ld", (long) char_offset));
88481                         match = 1;
88482                         break;
88483                 }
88484
88485                 /* advance by one character (code point) and one char_offset */
88486                 char_offset++;
88487                 if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) {
88488                         /*
88489                          *  Note:
88490                          *
88491                          *    - Intentionally attempt (empty) match at char_offset == k_input->clen
88492                          *
88493                          *    - Negative char_offsets have been eliminated and char_offset is duk_uint32_t
88494                          *      -> no need or use for a negative check
88495                          */
88496
88497                         DUK_DDD(DUK_DDDPRINT("no match after trying all sp offsets"));
88498                         break;
88499                 }
88500
88501                 /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */
88502                 (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1);
88503         }
88504
88505  match_over:
88506
88507         /*
88508          *  Matching complete, create result array or return a 'null'.  Update lastIndex
88509          *  if necessary.  See E5 Section 15.10.6.2.
88510          *
88511          *  Because lastIndex is a character (not byte) offset, we need the character
88512          *  length of the match which we conveniently get as a side effect of interning
88513          *  the matching substring (0th index of result array).
88514          *
88515          *  saved[0]         start pointer (~ byte offset) of current match
88516          *  saved[1]         end pointer (~ byte offset) of current match (exclusive)
88517          *  char_offset      start character offset of current match (-> .index of result)
88518          *  char_end_offset  end character offset (computed below)
88519          */
88520
88521         /* [ ... re_obj input bc saved_buf ] */
88522
88523         if (match) {
88524 #if defined(DUK_USE_ASSERTIONS)
88525                 duk_hobject *h_res;
88526 #endif
88527                 duk_uint32_t char_end_offset = 0;
88528
88529                 DUK_DDD(DUK_DDDPRINT("regexp matches at char_offset %ld", (long) char_offset));
88530
88531                 DUK_ASSERT(re_ctx.nsaved >= 2);        /* must have start and end */
88532                 DUK_ASSERT((re_ctx.nsaved % 2) == 0);  /* and even number */
88533
88534                 /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken
88535                  * advantage of now.  The array is not compacted either, as regexp match
88536                  * objects are usually short lived.
88537                  */
88538
88539                 duk_push_array(thr);
88540
88541 #if defined(DUK_USE_ASSERTIONS)
88542                 h_res = duk_require_hobject(thr, -1);
88543                 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
88544                 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res));
88545                 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
88546 #endif
88547
88548                 /* [ ... re_obj input bc saved_buf res_obj ] */
88549
88550                 duk_push_u32(thr, char_offset);
88551                 duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INDEX);
88552
88553                 duk_dup_m4(thr);
88554                 duk_xdef_prop_stridx_short_wec(thr, -2, DUK_STRIDX_INPUT);
88555
88556                 for (i = 0; i < re_ctx.nsaved; i += 2) {
88557                         /* Captures which are undefined have NULL pointers and are returned
88558                          * as 'undefined'.  The same is done when saved[] pointers are insane
88559                          * (this should, of course, never happen in practice).
88560                          */
88561                         if (re_ctx.saved[i] && re_ctx.saved[i + 1] && re_ctx.saved[i + 1] >= re_ctx.saved[i]) {
88562                                 duk_push_lstring(thr,
88563                                                  (const char *) re_ctx.saved[i],
88564                                                  (duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
88565                                 if (i == 0) {
88566                                         /* Assumes that saved[0] and saved[1] are always
88567                                          * set by regexp bytecode (if not, char_end_offset
88568                                          * will be zero).  Also assumes clen reflects the
88569                                          * correct char length.
88570                                          */
88571                                         char_end_offset = char_offset + (duk_uint32_t) duk_get_length(thr, -1);  /* add charlen */
88572                                 }
88573                         } else {
88574                                 duk_push_undefined(thr);
88575                         }
88576
88577                         /* [ ... re_obj input bc saved_buf res_obj val ] */
88578                         duk_put_prop_index(thr, -2, (duk_uarridx_t) (i / 2));
88579                 }
88580
88581                 /* [ ... re_obj input bc saved_buf res_obj ] */
88582
88583                 /* NB: 'length' property is automatically updated by the array setup loop */
88584
88585                 if (global) {
88586                         /* global regexp: lastIndex updated on match */
88587                         duk_push_u32(thr, char_end_offset);
88588                         duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX);
88589                 } else {
88590                         /* non-global regexp: lastIndex never updated on match */
88591                         ;
88592                 }
88593         } else {
88594                 /*
88595                  *  No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless
88596                  *  of 'global' flag of the RegExp.  In particular, if lastIndex is invalid
88597                  *  initially, it is reset to zero.
88598                  */
88599
88600                 DUK_DDD(DUK_DDDPRINT("regexp does not match"));
88601
88602                 duk_push_null(thr);
88603
88604                 /* [ ... re_obj input bc saved_buf res_obj ] */
88605
88606                 duk_push_int(thr, 0);
88607                 duk_put_prop_stridx_short(thr, -6, DUK_STRIDX_LAST_INDEX);
88608         }
88609
88610         /* [ ... re_obj input bc saved_buf res_obj ] */
88611
88612         duk_insert(thr, -5);
88613
88614         /* [ ... res_obj re_obj input bc saved_buf ] */
88615
88616         duk_pop_n_unsafe(thr, 4);
88617
88618         /* [ ... res_obj ] */
88619
88620         /* XXX: these last tricks are unnecessary if the function is made
88621          * a genuine native function.
88622          */
88623 }
88624
88625 DUK_INTERNAL void duk_regexp_match(duk_hthread *thr) {
88626         duk__regexp_match_helper(thr, 0 /*force_global*/);
88627 }
88628
88629 /* This variant is needed by String.prototype.split(); it needs to perform
88630  * global-style matching on a cloned RegExp which is potentially non-global.
88631  */
88632 DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
88633         duk__regexp_match_helper(thr, 1 /*force_global*/);
88634 }
88635
88636 #else  /* DUK_USE_REGEXP_SUPPORT */
88637
88638 /* regexp support disabled */
88639
88640 #endif  /* DUK_USE_REGEXP_SUPPORT */
88641 #line 1 "duk_selftest.c"
88642 /*
88643  *  Self tests to ensure execution environment is sane.  Intended to catch
88644  *  compiler/platform problems which cannot be detected at compile time.
88645  */
88646
88647 /* #include duk_internal.h -> already included */
88648
88649 #if defined(DUK_USE_SELF_TESTS)
88650
88651 /*
88652  *  Unions and structs for self tests
88653  */
88654
88655 typedef union {
88656         double d;
88657         duk_uint8_t x[8];
88658 } duk__test_double_union;
88659
88660 /* Self test failed.  Expects a local variable 'error_count' to exist. */
88661 #define DUK__FAILED(msg)  do { \
88662                 DUK_D(DUK_DPRINT("self test failed: " #msg " at " DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO))); \
88663                 error_count++; \
88664         } while (0)
88665
88666 #define DUK__DBLUNION_CMP_TRUE(a,b)  do { \
88667                 if (duk_memcmp((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
88668                         DUK__FAILED("double union compares false (expected true)"); \
88669                 } \
88670         } while (0)
88671
88672 #define DUK__DBLUNION_CMP_FALSE(a,b)  do { \
88673                 if (duk_memcmp((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
88674                         DUK__FAILED("double union compares true (expected false)"); \
88675                 } \
88676         } while (0)
88677
88678 typedef union {
88679         duk_uint32_t i;
88680         duk_uint8_t x[8];
88681 } duk__test_u32_union;
88682
88683 #if defined(DUK_USE_INTEGER_LE)
88684 #define DUK__U32_INIT(u, a, b, c, d) do { \
88685                 (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \
88686         } while (0)
88687 #elif defined(DUK_USE_INTEGER_ME)
88688 #error integer mixed endian not supported now
88689 #elif defined(DUK_USE_INTEGER_BE)
88690 #define DUK__U32_INIT(u, a, b, c, d) do { \
88691                 (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \
88692         } while (0)
88693 #else
88694 #error unknown integer endianness
88695 #endif
88696
88697 #if defined(DUK_USE_DOUBLE_LE)
88698 #define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
88699                 (u)->x[0] = (h); (u)->x[1] = (g); (u)->x[2] = (f); (u)->x[3] = (e); \
88700                 (u)->x[4] = (d); (u)->x[5] = (c); (u)->x[6] = (b); (u)->x[7] = (a); \
88701         } while (0)
88702 #define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
88703         ((u)->x[0] == (h) && (u)->x[1] == (g) && (u)->x[2] == (f) && (u)->x[3] == (e) && \
88704          (u)->x[4] == (d) && (u)->x[5] == (c) && (u)->x[6] == (b) && (u)->x[7] == (a))
88705 #elif defined(DUK_USE_DOUBLE_ME)
88706 #define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
88707                 (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \
88708                 (u)->x[4] = (h); (u)->x[5] = (g); (u)->x[6] = (f); (u)->x[7] = (e); \
88709         } while (0)
88710 #define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
88711         ((u)->x[0] == (d) && (u)->x[1] == (c) && (u)->x[2] == (b) && (u)->x[3] == (a) && \
88712          (u)->x[4] == (h) && (u)->x[5] == (g) && (u)->x[6] == (f) && (u)->x[7] == (e))
88713 #elif defined(DUK_USE_DOUBLE_BE)
88714 #define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
88715                 (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \
88716                 (u)->x[4] = (e); (u)->x[5] = (f); (u)->x[6] = (g); (u)->x[7] = (h); \
88717         } while (0)
88718 #define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
88719         ((u)->x[0] == (a) && (u)->x[1] == (b) && (u)->x[2] == (c) && (u)->x[3] == (d) && \
88720          (u)->x[4] == (e) && (u)->x[5] == (f) && (u)->x[6] == (g) && (u)->x[7] == (h))
88721 #else
88722 #error unknown double endianness
88723 #endif
88724
88725 /*
88726  *  Various sanity checks for typing
88727  */
88728
88729 DUK_LOCAL duk_uint_t duk__selftest_types(void) {
88730         duk_uint_t error_count = 0;
88731
88732         if (!(sizeof(duk_int8_t) == 1 &&
88733               sizeof(duk_uint8_t) == 1 &&
88734               sizeof(duk_int16_t) == 2 &&
88735               sizeof(duk_uint16_t) == 2 &&
88736               sizeof(duk_int32_t) == 4 &&
88737               sizeof(duk_uint32_t) == 4)) {
88738                 DUK__FAILED("duk_(u)int{8,16,32}_t size");
88739         }
88740 #if defined(DUK_USE_64BIT_OPS)
88741         if (!(sizeof(duk_int64_t) == 8 &&
88742               sizeof(duk_uint64_t) == 8)) {
88743                 DUK__FAILED("duk_(u)int64_t size");
88744         }
88745 #endif
88746
88747         if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) {
88748                 /* Some internal code now assumes that all duk_uint_t values
88749                  * can be expressed with a duk_size_t.
88750                  */
88751                 DUK__FAILED("duk_size_t is smaller than duk_uint_t");
88752         }
88753         if (!(sizeof(duk_int_t) >= 4)) {
88754                 DUK__FAILED("duk_int_t is not 32 bits");
88755         }
88756
88757         return error_count;
88758 }
88759
88760 /*
88761  *  Packed tval sanity
88762  */
88763
88764 DUK_LOCAL duk_uint_t duk__selftest_packed_tval(void) {
88765         duk_uint_t error_count = 0;
88766
88767 #if defined(DUK_USE_PACKED_TVAL)
88768         if (sizeof(void *) > 4) {
88769                 DUK__FAILED("packed duk_tval in use but sizeof(void *) > 4");
88770         }
88771 #endif
88772
88773         return error_count;
88774 }
88775
88776 /*
88777  *  Two's complement arithmetic.
88778  */
88779
88780 DUK_LOCAL duk_uint_t duk__selftest_twos_complement(void) {
88781         duk_uint_t error_count = 0;
88782         volatile int test;
88783         test = -1;
88784
88785         /* Note that byte order doesn't affect this test: all bytes in
88786          * 'test' will be 0xFF for two's complement.
88787          */
88788         if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
88789                 DUK__FAILED("two's complement arithmetic");
88790         }
88791
88792         return error_count;
88793 }
88794
88795 /*
88796  *  Byte order.  Important to self check, because on some exotic platforms
88797  *  there is no actual detection but rather assumption based on platform
88798  *  defines.
88799  */
88800
88801 DUK_LOCAL duk_uint_t duk__selftest_byte_order(void) {
88802         duk_uint_t error_count = 0;
88803         duk__test_u32_union u1;
88804         duk__test_double_union u2;
88805
88806         /*
88807          *  >>> struct.pack('>d', 102030405060).encode('hex')
88808          *  '4237c17c6dc40000'
88809          */
88810
88811         DUK__U32_INIT(&u1, 0xde, 0xad, 0xbe, 0xef);
88812         DUK__DOUBLE_INIT(&u2, 0x42, 0x37, 0xc1, 0x7c, 0x6d, 0xc4, 0x00, 0x00);
88813
88814         if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
88815                 DUK__FAILED("duk_uint32_t byte order");
88816         }
88817
88818         if (u2.d != (double) 102030405060.0) {
88819                 DUK__FAILED("double byte order");
88820         }
88821
88822         return error_count;
88823 }
88824
88825 /*
88826  *  DUK_BSWAP macros
88827  */
88828
88829 DUK_LOCAL duk_uint_t duk__selftest_bswap_macros(void) {
88830         duk_uint_t error_count = 0;
88831         duk_uint32_t x32;
88832         duk_uint16_t x16;
88833         duk_double_union du;
88834         duk_double_t du_diff;
88835
88836         x16 = 0xbeefUL;
88837         x16 = DUK_BSWAP16(x16);
88838         if (x16 != (duk_uint16_t) 0xefbeUL) {
88839                 DUK__FAILED("DUK_BSWAP16");
88840         }
88841
88842         x32 = 0xdeadbeefUL;
88843         x32 = DUK_BSWAP32(x32);
88844         if (x32 != (duk_uint32_t) 0xefbeaddeUL) {
88845                 DUK__FAILED("DUK_BSWAP32");
88846         }
88847
88848         /* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
88849          * (2.008366013071895,)
88850          */
88851
88852         du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22;
88853         du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66;
88854         DUK_DBLUNION_DOUBLE_NTOH(&du);
88855         du_diff = du.d - 2.008366013071895;
88856 #if 0
88857         DUK_D(DUK_DPRINT("du_diff: %lg\n", (double) du_diff));
88858 #endif
88859         if (du_diff > 1e-15) {
88860                 /* Allow very small lenience because some compilers won't parse
88861                  * exact IEEE double constants (happened in matrix testing with
88862                  * Linux gcc-4.8 -m32 at least).
88863                  */
88864 #if 0
88865                 DUK_D(DUK_DPRINT("Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
88866                             (unsigned int) du.uc[0], (unsigned int) du.uc[1],
88867                             (unsigned int) du.uc[2], (unsigned int) du.uc[3],
88868                             (unsigned int) du.uc[4], (unsigned int) du.uc[5],
88869                             (unsigned int) du.uc[6], (unsigned int) du.uc[7]));
88870 #endif
88871                 DUK__FAILED("DUK_DBLUNION_DOUBLE_NTOH");
88872         }
88873
88874         return error_count;
88875 }
88876
88877 /*
88878  *  Basic double / byte union memory layout.
88879  */
88880
88881 DUK_LOCAL duk_uint_t duk__selftest_double_union_size(void) {
88882         duk_uint_t error_count = 0;
88883
88884         if (sizeof(duk__test_double_union) != 8) {
88885                 DUK__FAILED("invalid union size");
88886         }
88887
88888         return error_count;
88889 }
88890
88891 /*
88892  *  Union aliasing, see misc/clang_aliasing.c.
88893  */
88894
88895 DUK_LOCAL duk_uint_t duk__selftest_double_aliasing(void) {
88896         /* This testcase fails when Emscripten-generated code runs on Firefox.
88897          * It's not an issue because the failure should only affect packed
88898          * duk_tval representation, which is not used with Emscripten.
88899          */
88900 #if defined(DUK_USE_PACKED_TVAL)
88901         duk_uint_t error_count = 0;
88902         duk__test_double_union a, b;
88903
88904         /* Test signaling NaN and alias assignment in all endianness combinations.
88905          */
88906
88907         /* little endian */
88908         a.x[0] = 0x11; a.x[1] = 0x22; a.x[2] = 0x33; a.x[3] = 0x44;
88909         a.x[4] = 0x00; a.x[5] = 0x00; a.x[6] = 0xf1; a.x[7] = 0xff;
88910         b = a;
88911         DUK__DBLUNION_CMP_TRUE(&a, &b);
88912
88913         /* big endian */
88914         a.x[0] = 0xff; a.x[1] = 0xf1; a.x[2] = 0x00; a.x[3] = 0x00;
88915         a.x[4] = 0x44; a.x[5] = 0x33; a.x[6] = 0x22; a.x[7] = 0x11;
88916         b = a;
88917         DUK__DBLUNION_CMP_TRUE(&a, &b);
88918
88919         /* mixed endian */
88920         a.x[0] = 0x00; a.x[1] = 0x00; a.x[2] = 0xf1; a.x[3] = 0xff;
88921         a.x[4] = 0x11; a.x[5] = 0x22; a.x[6] = 0x33; a.x[7] = 0x44;
88922         b = a;
88923         DUK__DBLUNION_CMP_TRUE(&a, &b);
88924
88925         return error_count;
88926 #else
88927         DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
88928         return 0;
88929 #endif
88930 }
88931
88932 /*
88933  *  Zero sign, see misc/tcc_zerosign2.c.
88934  */
88935
88936 DUK_LOCAL duk_uint_t duk__selftest_double_zero_sign(void) {
88937         duk_uint_t error_count = 0;
88938         duk__test_double_union a, b;
88939
88940         a.d = 0.0;
88941         b.d = -a.d;
88942         DUK__DBLUNION_CMP_FALSE(&a, &b);
88943
88944         return error_count;
88945 }
88946
88947 /*
88948  *  Rounding mode: Duktape assumes round-to-nearest, check that this is true.
88949  *  If we had C99 fenv.h we could check that fegetround() == FE_TONEAREST,
88950  *  but we don't want to rely on that header; and even if we did, it's good
88951  *  to ensure the rounding actually works.
88952  */
88953
88954 DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) {
88955         duk_uint_t error_count = 0;
88956         duk__test_double_union a, b, c;
88957
88958 #if 0
88959         /* Include <fenv.h> and test manually; these trigger failures: */
88960         fesetround(FE_UPWARD);
88961         fesetround(FE_DOWNWARD);
88962         fesetround(FE_TOWARDZERO);
88963
88964         /* This is the default and passes. */
88965         fesetround(FE_TONEAREST);
88966 #endif
88967
88968         /* Rounding tests check that none of the other modes (round to
88969          * +Inf, round to -Inf, round to zero) can be active:
88970          * http://www.gnu.org/software/libc/manual/html_node/Rounding.html
88971          */
88972
88973         /* 1.0 + 2^(-53): result is midway between 1.0 and 1.0 + ulp.
88974          * Round to nearest: 1.0
88975          * Round to +Inf:    1.0 + ulp
88976          * Round to -Inf:    1.0
88977          * Round to zero:    1.0
88978          * => Correct result eliminates round to +Inf.
88979          */
88980         DUK__DOUBLE_INIT(&a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
88981         DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
88982         duk_memset((void *) &c, 0, sizeof(c));
88983         c.d = a.d + b.d;
88984         if (!DUK__DOUBLE_COMPARE(&c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)) {
88985                 DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x",
88986                                  (unsigned int) c.x[0], (unsigned int) c.x[1],
88987                                  (unsigned int) c.x[2], (unsigned int) c.x[3],
88988                                  (unsigned int) c.x[4], (unsigned int) c.x[5],
88989                                  (unsigned int) c.x[6], (unsigned int) c.x[7]));
88990                 DUK__FAILED("invalid result from 1.0 + 0.5ulp");
88991         }
88992
88993         /* (1.0 + ulp) + 2^(-53): result is midway between 1.0 + ulp and 1.0 + 2*ulp.
88994          * Round to nearest: 1.0 + 2*ulp (round to even mantissa)
88995          * Round to +Inf:    1.0 + 2*ulp
88996          * Round to -Inf:    1.0 + ulp
88997          * Round to zero:    1.0 + ulp
88998          * => Correct result eliminates round to -Inf and round to zero.
88999          */
89000         DUK__DOUBLE_INIT(&a, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
89001         DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
89002         duk_memset((void *) &c, 0, sizeof(c));
89003         c.d = a.d + b.d;
89004         if (!DUK__DOUBLE_COMPARE(&c, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02)) {
89005                 DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x",
89006                                  (unsigned int) c.x[0], (unsigned int) c.x[1],
89007                                  (unsigned int) c.x[2], (unsigned int) c.x[3],
89008                                  (unsigned int) c.x[4], (unsigned int) c.x[5],
89009                                  (unsigned int) c.x[6], (unsigned int) c.x[7]));
89010                 DUK__FAILED("invalid result from (1.0 + ulp) + 0.5ulp");
89011         }
89012
89013         /* Could do negative number testing too, but the tests above should
89014          * differentiate between IEEE 754 rounding modes.
89015          */
89016         return error_count;
89017 }
89018
89019 /*
89020  *  fmod(): often a portability issue in embedded or bare platform targets.
89021  *  Check for at least minimally correct behavior.  Unlike some other math
89022  *  functions (like cos()) Duktape relies on fmod() internally too.
89023  */
89024
89025 DUK_LOCAL duk_uint_t duk__selftest_fmod(void) {
89026         duk_uint_t error_count = 0;
89027         duk__test_double_union u1, u2;
89028         volatile duk_double_t t1, t2, t3;
89029
89030         /* fmod() with integer argument and exponent 2^32 is used by e.g.
89031          * ToUint32() and some Duktape internals.
89032          */
89033         u1.d = DUK_FMOD(10.0, 4294967296.0);
89034         u2.d = 10.0;
89035         DUK__DBLUNION_CMP_TRUE(&u1, &u2);
89036
89037         u1.d = DUK_FMOD(4294967306.0, 4294967296.0);
89038         u2.d = 10.0;
89039         DUK__DBLUNION_CMP_TRUE(&u1, &u2);
89040
89041         u1.d = DUK_FMOD(73014444042.0, 4294967296.0);
89042         u2.d = 10.0;
89043         DUK__DBLUNION_CMP_TRUE(&u1, &u2);
89044
89045         /* 52-bit integer split into two parts:
89046          * >>> 0x1fedcba9876543
89047          * 8987183256397123
89048          * >>> float(0x1fedcba9876543) / float(2**53)
89049          * 0.9977777777777778
89050          */
89051         u1.d = DUK_FMOD(8987183256397123.0, 4294967296.0);
89052         u2.d = (duk_double_t) 0xa9876543UL;
89053         DUK__DBLUNION_CMP_TRUE(&u1, &u2);
89054         t1 = 8987183256397123.0;
89055         t2 = 4294967296.0;
89056         t3 = t1 / t2;
89057         u1.d = DUK_FLOOR(t3);
89058         u2.d = (duk_double_t) 0x1fedcbUL;
89059         DUK__DBLUNION_CMP_TRUE(&u1, &u2);
89060
89061         /* C99 behavior is for fmod() result sign to mathc argument sign. */
89062         u1.d = DUK_FMOD(-10.0, 4294967296.0);
89063         u2.d = -10.0;
89064         DUK__DBLUNION_CMP_TRUE(&u1, &u2);
89065
89066         u1.d = DUK_FMOD(-4294967306.0, 4294967296.0);
89067         u2.d = -10.0;
89068         DUK__DBLUNION_CMP_TRUE(&u1, &u2);
89069
89070         u1.d = DUK_FMOD(-73014444042.0, 4294967296.0);
89071         u2.d = -10.0;
89072         DUK__DBLUNION_CMP_TRUE(&u1, &u2);
89073
89074         return error_count;
89075 }
89076
89077 /*
89078  *  Struct size/alignment if platform requires it
89079  *
89080  *  There are some compiler specific struct padding pragmas etc in use, this
89081  *  selftest ensures they're correctly detected and used.
89082  */
89083
89084 DUK_LOCAL duk_uint_t duk__selftest_struct_align(void) {
89085         duk_uint_t error_count = 0;
89086
89087 #if (DUK_USE_ALIGN_BY == 4)
89088         if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
89089                 DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 4");
89090         }
89091 #elif (DUK_USE_ALIGN_BY == 8)
89092         if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
89093                 DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 8");
89094         }
89095 #elif (DUK_USE_ALIGN_BY == 1)
89096         /* no check */
89097 #else
89098 #error invalid DUK_USE_ALIGN_BY
89099 #endif
89100         return error_count;
89101 }
89102
89103 /*
89104  *  64-bit arithmetic
89105  *
89106  *  There are some platforms/compilers where 64-bit types are available
89107  *  but don't work correctly.  Test for known cases.
89108  */
89109
89110 DUK_LOCAL duk_uint_t duk__selftest_64bit_arithmetic(void) {
89111         duk_uint_t error_count = 0;
89112 #if defined(DUK_USE_64BIT_OPS)
89113         volatile duk_int64_t i;
89114         volatile duk_double_t d;
89115
89116         /* Catch a double-to-int64 cast issue encountered in practice. */
89117         d = 2147483648.0;
89118         i = (duk_int64_t) d;
89119         if (i != DUK_I64_CONSTANT(0x80000000)) {
89120                 DUK__FAILED("casting 2147483648.0 to duk_int64_t failed");
89121         }
89122 #else
89123         /* nop */
89124 #endif
89125         return error_count;
89126 }
89127
89128 /*
89129  *  Casting
89130  */
89131
89132 DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_small_uint(void) {
89133         /*
89134          *  https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
89135          */
89136
89137         duk_uint_t error_count = 0;
89138
89139         duk_double_t d1, d2;
89140         duk_small_uint_t u;
89141
89142         duk_double_t d1v, d2v;
89143         duk_small_uint_t uv;
89144
89145         /* Test without volatiles */
89146
89147         d1 = 1.0;
89148         u = (duk_small_uint_t) d1;
89149         d2 = (duk_double_t) u;
89150
89151         if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) {
89152                 DUK__FAILED("double to duk_small_uint_t cast failed");
89153         }
89154
89155         /* Same test with volatiles */
89156
89157         d1v = 1.0;
89158         uv = (duk_small_uint_t) d1v;
89159         d2v = (duk_double_t) uv;
89160
89161         if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) {
89162                 DUK__FAILED("double to duk_small_uint_t cast failed");
89163         }
89164
89165         return error_count;
89166 }
89167
89168 DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_uint32(void) {
89169         /*
89170          *  This test fails on an exotic ARM target; double-to-uint
89171          *  cast is incorrectly clamped to -signed- int highest value.
89172          *
89173          *  https://github.com/svaarala/duktape/issues/336
89174          */
89175
89176         duk_uint_t error_count = 0;
89177         duk_double_t dv;
89178         duk_uint32_t uv;
89179
89180         dv = 3735928559.0;  /* 0xdeadbeef in decimal */
89181         uv = (duk_uint32_t) dv;
89182
89183         if (uv != 0xdeadbeefUL) {
89184                 DUK__FAILED("double to duk_uint32_t cast failed");
89185         }
89186
89187         return error_count;
89188 }
89189
89190 /*
89191  *  Minimal test of user supplied allocation functions
89192  *
89193  *    - Basic alloc + realloc + free cycle
89194  *
89195  *    - Realloc to significantly larger size to (hopefully) trigger a
89196  *      relocation and check that relocation copying works
89197  */
89198
89199 DUK_LOCAL duk_uint_t duk__selftest_alloc_funcs(duk_alloc_function alloc_func,
89200                                                duk_realloc_function realloc_func,
89201                                                duk_free_function free_func,
89202                                                void *udata) {
89203         duk_uint_t error_count = 0;
89204         void *ptr;
89205         void *new_ptr;
89206         duk_small_int_t i, j;
89207         unsigned char x;
89208
89209         if (alloc_func == NULL || realloc_func == NULL || free_func == NULL) {
89210                 return 0;
89211         }
89212
89213         for (i = 1; i <= 256; i++) {
89214                 ptr = alloc_func(udata, (duk_size_t) i);
89215                 if (ptr == NULL) {
89216                         DUK_D(DUK_DPRINT("alloc failed, ignore"));
89217                         continue;  /* alloc failed, ignore */
89218                 }
89219                 for (j = 0; j < i; j++) {
89220                         ((unsigned char *) ptr)[j] = (unsigned char) (0x80 + j);
89221                 }
89222                 new_ptr = realloc_func(udata, ptr, 1024);
89223                 if (new_ptr == NULL) {
89224                         DUK_D(DUK_DPRINT("realloc failed, ignore"));
89225                         free_func(udata, ptr);
89226                         continue;  /* realloc failed, ignore */
89227                 }
89228                 ptr = new_ptr;
89229                 for (j = 0; j < i; j++) {
89230                         x = ((unsigned char *) ptr)[j];
89231                         if (x != (unsigned char) (0x80 + j)) {
89232                                 DUK_D(DUK_DPRINT("byte at index %ld doesn't match after realloc: %02lx",
89233                                                  (long) j, (unsigned long) x));
89234                                 DUK__FAILED("byte compare after realloc");
89235                                 break;
89236                         }
89237                 }
89238                 free_func(udata, ptr);
89239         }
89240
89241         return error_count;
89242 }
89243
89244 /*
89245  *  Self test main
89246  */
89247
89248 DUK_INTERNAL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
89249                                                duk_realloc_function realloc_func,
89250                                                duk_free_function free_func,
89251                                                void *udata) {
89252         duk_uint_t error_count = 0;
89253
89254         DUK_D(DUK_DPRINT("self test starting"));
89255
89256         error_count += duk__selftest_types();
89257         error_count += duk__selftest_packed_tval();
89258         error_count += duk__selftest_twos_complement();
89259         error_count += duk__selftest_byte_order();
89260         error_count += duk__selftest_bswap_macros();
89261         error_count += duk__selftest_double_union_size();
89262         error_count += duk__selftest_double_aliasing();
89263         error_count += duk__selftest_double_zero_sign();
89264         error_count += duk__selftest_double_rounding();
89265         error_count += duk__selftest_fmod();
89266         error_count += duk__selftest_struct_align();
89267         error_count += duk__selftest_64bit_arithmetic();
89268         error_count += duk__selftest_cast_double_to_small_uint();
89269         error_count += duk__selftest_cast_double_to_uint32();
89270         error_count += duk__selftest_alloc_funcs(alloc_func, realloc_func, free_func, udata);
89271
89272         DUK_D(DUK_DPRINT("self test complete, total error count: %ld", (long) error_count));
89273
89274         return error_count;
89275 }
89276
89277 #endif  /* DUK_USE_SELF_TESTS */
89278
89279 /* automatic undefs */
89280 #undef DUK__DBLUNION_CMP_FALSE
89281 #undef DUK__DBLUNION_CMP_TRUE
89282 #undef DUK__DOUBLE_COMPARE
89283 #undef DUK__DOUBLE_INIT
89284 #undef DUK__FAILED
89285 #undef DUK__U32_INIT
89286 /* #include duk_internal.h -> already included */
89287 #line 2 "duk_tval.c"
89288
89289 #if defined(DUK_USE_FASTINT)
89290
89291 /*
89292  *  Manually optimized double-to-fastint downgrade check.
89293  *
89294  *  This check has a large impact on performance, especially for fastint
89295  *  slow paths, so must be changed carefully.  The code should probably be
89296  *  optimized for the case where the result does not fit into a fastint,
89297  *  to minimize the penalty for "slow path code" dealing with fractions etc.
89298  *
89299  *  At least on one tested soft float ARM platform double-to-int64 coercion
89300  *  is very slow (and sometimes produces incorrect results, see self tests).
89301  *  This algorithm combines a fastint compatibility check and extracting the
89302  *  integer value from an IEEE double for setting the tagged fastint.  For
89303  *  other platforms a more naive approach might be better.
89304  *
89305  *  See doc/fastint.rst for details.
89306  */
89307
89308 DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x) {
89309         duk_double_union du;
89310         duk_int64_t i;
89311         duk_small_int_t expt;
89312         duk_small_int_t shift;
89313
89314         /* XXX: optimize for packed duk_tval directly? */
89315
89316         du.d = x;
89317         i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du);
89318         expt = (duk_small_int_t) ((i >> 52) & 0x07ff);
89319         shift = expt - 1023;
89320
89321         if (shift >= 0 && shift <= 46) {  /* exponents 1023 to 1069 */
89322                 duk_int64_t t;
89323
89324                 if (((DUK_I64_CONSTANT(0x000fffffffffffff) >> shift) & i) == 0) {
89325                         t = i | DUK_I64_CONSTANT(0x0010000000000000);  /* implicit leading one */
89326                         t = t & DUK_I64_CONSTANT(0x001fffffffffffff);
89327                         t = t >> (52 - shift);
89328                         if (i < 0) {
89329                                 t = -t;
89330                         }
89331                         DUK_TVAL_SET_FASTINT(tv, t);
89332                         return;
89333                 }
89334         } else if (shift == -1023) {  /* exponent 0 */
89335                 if (i >= 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
89336                         /* Note: reject negative zero. */
89337                         DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
89338                         return;
89339                 }
89340         } else if (shift == 47) {  /* exponent 1070 */
89341                 if (i < 0 && (i & DUK_I64_CONSTANT(0x000fffffffffffff)) == 0) {
89342                         DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
89343                         return;
89344                 }
89345         }
89346
89347         DUK_TVAL_SET_DOUBLE(tv, x);
89348         return;
89349 }
89350
89351 DUK_INTERNAL DUK_NOINLINE void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x) {
89352         duk_tval_set_number_chkfast_fast(tv, x);
89353 }
89354
89355 /*
89356  *  Manually optimized number-to-double conversion
89357  */
89358
89359 #if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL)
89360 DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) {
89361         duk_double_union du;
89362         duk_uint64_t t;
89363
89364         t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
89365         if ((t >> 48) != DUK_TAG_FASTINT) {
89366                 return tv->d;
89367         } else if (t & DUK_U64_CONSTANT(0x0000800000000000)) {
89368                 t = (duk_uint64_t) (-((duk_int64_t) t));  /* avoid unary minus on unsigned */
89369                 t = t & DUK_U64_CONSTANT(0x0000ffffffffffff);  /* negative */
89370                 t |= DUK_U64_CONSTANT(0xc330000000000000);
89371                 DUK_DBLUNION_SET_UINT64(&du, t);
89372                 return du.d + 4503599627370496.0;  /* 1 << 52 */
89373         } else if (t != 0) {
89374                 t &= DUK_U64_CONSTANT(0x0000ffffffffffff);  /* positive */
89375                 t |= DUK_U64_CONSTANT(0x4330000000000000);
89376                 DUK_DBLUNION_SET_UINT64(&du, t);
89377                 return du.d - 4503599627370496.0;  /* 1 << 52 */
89378         } else {
89379                 return 0.0;  /* zero */
89380         }
89381 }
89382 #endif  /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
89383
89384 #if 0  /* unused */
89385 #if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
89386 DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) {
89387         duk_double_union du;
89388         duk_uint64_t t;
89389
89390         DUK_ASSERT(tv->t == DUK_TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
89391
89392         if (tv->t == DUK_TAG_FASTINT) {
89393                 if (tv->v.fi >= 0) {
89394                         t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
89395                         DUK_DBLUNION_SET_UINT64(&du, t);
89396                         return du.d - 4503599627370496.0;  /* 1 << 52 */
89397                 } else {
89398                         t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
89399                         DUK_DBLUNION_SET_UINT64(&du, t);
89400                         return du.d + 4503599627370496.0;  /* 1 << 52 */
89401                 }
89402         } else {
89403                 return tv->v.d;
89404         }
89405 }
89406 #endif  /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
89407 #endif  /* 0 */
89408
89409 #if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
89410 DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) {
89411         duk_double_union du;
89412         duk_uint64_t t;
89413
89414         DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
89415
89416         if (tv->v.fi >= 0) {
89417                 t = DUK_U64_CONSTANT(0x4330000000000000) | (duk_uint64_t) tv->v.fi;
89418                 DUK_DBLUNION_SET_UINT64(&du, t);
89419                 return du.d - 4503599627370496.0;  /* 1 << 52 */
89420         } else {
89421                 t = DUK_U64_CONSTANT(0xc330000000000000) | (duk_uint64_t) (-tv->v.fi);
89422                 DUK_DBLUNION_SET_UINT64(&du, t);
89423                 return du.d + 4503599627370496.0;  /* 1 << 52 */
89424         }
89425 }
89426 #endif  /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
89427
89428 #endif  /* DUK_USE_FASTINT */
89429 #line 1 "duk_unicode_tables.c"
89430 /*
89431  *  Unicode support tables automatically generated during build.
89432  */
89433
89434 /* #include duk_internal.h -> already included */
89435
89436 /*
89437  *  Unicode tables containing ranges of Unicode characters in a
89438  *  packed format.  These tables are used to match non-ASCII
89439  *  characters of complex productions by resorting to a linear
89440  *  range-by-range comparison.  This is very slow, but is expected
89441  *  to be very rare in practical ECMAScript source code, and thus
89442  *  compactness is most important.
89443  *
89444  *  The tables are matched using uni_range_match() and the format
89445  *  is described in tools/extract_chars.py.
89446  */
89447
89448 #if defined(DUK_USE_SOURCE_NONBMP)
89449 /* IdentifierStart production with ASCII excluded */
89450 /* duk_unicode_ids_noa[] */
89451 /*
89452  *  Automatically generated by extract_chars.py, do not edit!
89453  */
89454
89455 const duk_uint8_t duk_unicode_ids_noa[1063] = {
89456 249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34,
89457 2,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191,
89458 21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
89459 101,10,4,15,9,240,152,175,39,240,82,127,56,242,100,15,4,8,159,1,240,5,115,
89460 19,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,
89461 47,2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,
89462 18,47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,
89463 12,38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,
89464 6,41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,
89465 98,34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,
89466 2,85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,
89467 35,63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,
89468 227,240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,
89469 21,5,15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,
89470 175,40,240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,
89471 79,27,43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,
89472 32,47,15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,
89473 32,68,112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,
89474 87,52,29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,
89475 254,12,146,240,184,132,52,95,70,114,47,74,35,111,26,63,78,240,63,11,242,
89476 127,0,255,224,244,255,240,0,138,143,60,255,240,4,13,223,7,255,227,127,243,
89477 95,30,63,253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,
89478 243,26,34,35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,
89479 143,31,240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,
89480 48,32,240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,
89481 223,7,95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,
89482 18,245,207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,
89483 127,10,207,73,69,53,53,50,241,91,47,10,47,3,33,46,61,241,79,107,243,127,37,
89484 255,223,13,79,33,242,31,16,239,14,111,22,191,14,63,20,87,36,241,207,142,
89485 240,79,20,95,20,95,24,159,36,248,239,254,2,154,240,107,127,138,83,2,241,
89486 194,20,3,240,123,240,122,240,255,51,240,50,27,240,107,240,175,56,242,135,
89487 31,50,15,1,50,34,240,191,30,240,212,240,223,21,114,240,207,13,242,107,240,
89488 107,240,62,240,47,96,243,159,41,242,62,242,63,254,32,79,37,243,223,29,241,
89489 47,9,240,207,20,241,191,19,64,223,32,240,3,240,112,32,241,95,2,47,9,244,
89490 102,32,35,46,41,143,31,241,135,49,63,6,38,33,36,64,240,64,212,249,15,37,
89491 240,67,242,127,32,240,97,32,250,175,31,241,179,241,111,32,240,96,242,223,
89492 27,244,127,10,255,224,122,243,15,17,15,242,11,241,136,15,7,12,241,131,63,
89493 40,242,159,249,130,241,95,3,15,35,240,239,98,98,18,241,111,7,15,254,26,223,
89494 254,40,207,88,245,255,3,251,79,254,155,15,254,50,31,254,236,95,254,19,159,
89495 255,0,16,173,255,225,43,143,15,246,63,14,240,79,32,240,35,241,31,5,111,3,
89496 255,226,100,243,92,15,52,207,50,31,16,255,240,0,109,255,5,255,225,229,255,
89497 240,1,64,31,254,1,31,67,255,224,126,255,231,248,245,182,196,136,159,255,0,
89498 6,90,244,82,243,114,19,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4,
89499 98,255,224,70,63,9,47,9,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255,
89500 239,40,251,95,45,243,79,254,59,3,47,11,33,32,48,41,35,32,32,112,80,32,32,
89501 34,33,32,48,32,32,32,32,33,32,51,38,35,35,32,41,47,1,98,36,47,1,255,240,0,
89502 3,143,255,0,149,201,241,191,254,242,124,252,227,255,240,0,87,79,0,255,240,
89503 0,194,63,254,177,63,254,17,0,
89504 };
89505 #else
89506 /* IdentifierStart production with ASCII and non-BMP excluded */
89507 /* duk_unicode_ids_noabmp[] */
89508 /*
89509  *  Automatically generated by extract_chars.py, do not edit!
89510  */
89511
89512 const duk_uint8_t duk_unicode_ids_noabmp[626] = {
89513 249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34,
89514 2,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191,
89515 21,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
89516 101,10,4,15,9,240,152,175,39,240,82,127,56,242,100,15,4,8,159,1,240,5,115,
89517 19,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,
89518 47,2,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,
89519 18,47,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,
89520 12,38,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,
89521 6,41,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,
89522 98,34,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,
89523 2,85,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,
89524 35,63,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,
89525 227,240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,
89526 21,5,15,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,
89527 175,40,240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,
89528 79,27,43,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,
89529 32,47,15,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,
89530 32,68,112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,
89531 87,52,29,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,
89532 254,12,146,240,184,132,52,95,70,114,47,74,35,111,26,63,78,240,63,11,242,
89533 127,0,255,224,244,255,240,0,138,143,60,255,240,4,13,223,7,255,227,127,243,
89534 95,30,63,253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,
89535 243,26,34,35,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,
89536 143,31,240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,
89537 48,32,240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,
89538 223,7,95,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,
89539 18,245,207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,
89540 127,10,207,73,69,53,53,50,0,
89541 };
89542 #endif
89543
89544 #if defined(DUK_USE_SOURCE_NONBMP)
89545 /* IdentifierStart production with Letter and ASCII excluded */
89546 /* duk_unicode_ids_m_let_noa[] */
89547 /*
89548  *  Automatically generated by extract_chars.py, do not edit!
89549  */
89550
89551 const duk_uint8_t duk_unicode_ids_m_let_noa[42] = {
89552 255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
89553 249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,240,
89554 };
89555 #else
89556 /* IdentifierStart production with Letter, ASCII, and non-BMP excluded */
89557 /* duk_unicode_ids_m_let_noabmp[] */
89558 /*
89559  *  Automatically generated by extract_chars.py, do not edit!
89560  */
89561
89562 const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = {
89563 255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
89564 249,0,
89565 };
89566 #endif
89567
89568 #if defined(DUK_USE_SOURCE_NONBMP)
89569 /* IdentifierPart production with IdentifierStart and ASCII excluded */
89570 /* duk_unicode_idp_m_ids_noa[] */
89571 /*
89572  *  Automatically generated by extract_chars.py, do not edit!
89573  */
89574
89575 const duk_uint8_t duk_unicode_idp_m_ids_noa[549] = {
89576 255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
89577 245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
89578 36,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50,
89579 160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,
89580 97,57,181,34,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,
89581 240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,35,
89582 242,145,38,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,
89583 41,244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,
89584 245,111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,
89585 241,241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,
89586 242,244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,
89587 57,241,237,242,47,4,153,121,246,130,47,5,80,82,50,251,143,42,36,255,225,0,
89588 31,35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,
89589 31,255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,
89590 242,79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,
89591 29,208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3,
89592 225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,15,254,27,16,253,64,
89593 248,116,255,224,25,159,254,68,178,33,99,241,162,80,249,113,255,228,13,47,
89594 39,239,17,159,1,63,31,175,39,151,47,22,210,159,37,13,47,34,218,36,159,68,
89595 183,15,146,182,151,63,42,2,99,19,42,11,19,100,79,178,240,42,159,72,240,77,
89596 159,199,99,143,13,31,68,240,31,1,159,67,201,159,69,229,159,254,9,169,255,
89597 224,11,159,26,98,57,10,175,32,240,15,254,8,151,39,240,41,242,175,6,45,246,
89598 197,64,33,38,32,153,255,240,3,191,169,247,132,242,214,240,185,255,226,235,
89599 241,239,2,63,255,0,59,254,31,255,0,3,186,68,89,115,111,16,63,134,47,254,71,
89600 223,34,255,224,244,242,117,242,41,15,0,15,8,66,239,254,68,70,47,1,54,33,36,
89601 255,231,153,111,95,102,159,255,12,6,154,254,0,
89602 };
89603 #else
89604 /* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */
89605 /* duk_unicode_idp_m_ids_noabmp[] */
89606 /*
89607  *  Automatically generated by extract_chars.py, do not edit!
89608  */
89609
89610 const duk_uint8_t duk_unicode_idp_m_ids_noabmp[358] = {
89611 255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
89612 245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
89613 36,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50,
89614 160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,
89615 97,57,181,34,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,
89616 240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,35,
89617 242,145,38,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,
89618 41,244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,
89619 245,111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,
89620 241,241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,
89621 242,244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,
89622 57,241,237,242,47,4,153,121,246,130,47,5,80,82,50,251,143,42,36,255,225,0,
89623 31,35,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,
89624 31,255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,
89625 242,79,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,
89626 29,208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3,
89627 225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,0,
89628 };
89629 #endif
89630
89631 /*
89632  *  Case conversion tables generated using tools/extract_caseconv.py.
89633  */
89634
89635 /* duk_unicode_caseconv_uc[] */
89636 /* duk_unicode_caseconv_lc[] */
89637
89638 /*
89639  *  Automatically generated by extract_caseconv.py, do not edit!
89640  */
89641
89642 const duk_uint8_t duk_unicode_caseconv_uc[1386] = {
89643 144,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
89644 128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30,
89645 104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,9,252,9,248,6,28,131,4,
89646 33,4,62,0,62,16,32,124,64,124,96,48,249,0,249,64,129,243,1,243,129,3,232,3,
89647 233,1,135,216,7,218,4,15,184,15,221,2,31,114,31,200,8,62,236,63,180,8,125,
89648 224,127,224,16,251,208,255,80,33,247,193,255,160,67,246,3,247,0,135,244,7,
89649 246,1,15,240,15,244,2,33,112,33,96,32,73,160,73,108,104,176,192,176,1,121,
89650 104,0,133,2,106,183,1,58,10,31,232,63,228,38,162,1,1,1,0,48,2,102,2,100,12,
89651 4,232,4,228,64,10,88,10,81,112,23,160,23,144,96,48,96,48,64,128,104,64,104,
89652 1,128,218,0,217,130,1,206,1,205,16,3,190,3,188,36,7,228,7,224,160,17,24,17,
89653 16,144,36,112,36,96,160,110,32,110,0,128,246,64,246,6,2,48,130,48,17,4,139,
89654 4,138,54,9,132,9,130,28,19,68,19,65,128,240,8,240,4,177,234,17,234,6,3,234,
89655 35,235,33,11,26,11,25,193,150,64,150,64,50,44,236,44,235,5,76,131,76,128,
89656 94,154,6,154,0,117,57,29,57,16,122,115,58,115,35,244,239,84,239,32,169,223,
89657 233,223,130,211,200,211,200,2,167,151,167,150,21,79,107,79,104,8,112,26,
89658 208,26,192,64,56,160,56,128,192,113,128,113,1,128,249,0,248,130,2,128,1,
89659 166,4,7,240,7,238,8,177,204,177,200,16,96,49,0,48,224,128,110,64,110,1,1,
89660 51,83,213,2,0,48,35,192,35,176,64,77,32,50,192,139,73,196,49,193,127,48,2,
89661 212,14,112,3,252,5,224,4,196,1,36,5,252,1,76,6,0,9,12,6,72,6,68,6,84,7,216,
89662 6,100,6,96,6,104,8,244,6,120,8,128,6,160,6,156,6,252,7,220,7,116,6,56,7,
89663 204,7,196,9,64,177,188,9,68,177,180,9,72,177,192,9,76,6,4,9,80,6,24,9,100,
89664 6,60,9,108,6,64,9,114,158,172,9,128,6,76,9,134,158,176,9,140,6,80,9,150,
89665 158,52,9,160,6,92,9,172,177,136,9,178,158,180,9,196,177,184,9,200,6,116,9,
89666 212,6,124,9,244,177,144,10,30,158,196,10,32,6,184,10,36,9,16,10,48,9,20,10,
89667 72,6,220,10,118,158,200,10,122,158,192,13,20,14,100,13,220,13,216,14,176,
89668 14,24,15,8,14,140,15,48,14,48,15,64,14,72,15,68,14,96,15,84,14,152,15,88,
89669 14,128,15,92,15,60,15,192,14,104,15,196,14,132,15,200,15,228,15,204,13,252,
89670 15,212,14,84,19,60,19,0,114,0,16,72,114,4,16,80,114,8,16,120,114,20,16,136,
89671 114,24,16,168,114,28,17,136,114,34,153,40,117,230,157,244,117,244,177,140,
89672 122,108,121,128,126,248,14,100,127,148,127,176,133,56,132,200,134,16,134,
89673 12,177,132,177,128,177,148,8,232,177,152,8,248,179,204,179,202,158,50,158,
89674 46,173,78,158,207,48,6,252,0,166,0,166,2,147,1,94,0,39,0,248,64,9,64,97,
89675 128,114,24,28,200,24,64,24,8,29,134,7,74,6,16,6,2,11,15,2,154,130,169,15,
89676 75,64,9,0,102,35,210,240,2,160,24,64,244,196,0,174,6,20,61,51,0,44,129,133,
89677 15,77,64,8,32,87,195,234,16,29,40,24,152,250,150,7,74,6,38,6,0,62,169,129,
89678 210,129,137,129,128,143,171,96,116,160,98,96,104,67,240,16,248,64,28,200,
89679 252,12,62,18,7,50,63,5,15,133,1,204,143,193,195,225,96,115,35,240,144,248,
89680 96,28,200,252,44,62,26,7,50,63,13,15,135,1,204,143,195,195,225,224,115,35,
89681 241,16,248,64,28,200,252,76,62,18,7,50,63,21,15,133,1,204,143,197,195,225,
89682 96,115,35,241,144,248,96,28,200,252,108,62,26,7,50,63,29,15,135,1,204,143,
89683 199,195,225,224,115,35,242,16,249,64,28,200,252,140,62,82,7,50,63,37,15,
89684 149,1,204,143,201,195,229,96,115,35,242,144,249,96,28,200,252,172,62,90,7,
89685 50,63,45,15,151,1,204,143,203,195,229,224,115,35,243,16,249,64,28,200,252,
89686 204,62,82,7,50,63,53,15,149,1,204,143,205,195,229,96,115,35,243,144,249,96,
89687 28,200,252,236,62,90,7,50,63,61,15,151,1,204,143,207,195,229,224,115,35,
89688 244,16,251,64,28,200,253,12,62,210,7,50,63,69,15,181,1,204,143,209,195,237,
89689 96,115,35,244,144,251,96,28,200,253,44,62,218,7,50,63,77,15,183,1,204,143,
89690 211,195,237,224,115,35,245,16,251,64,28,200,253,76,62,210,7,50,63,85,15,
89691 181,1,204,143,213,195,237,96,115,35,245,144,251,96,28,200,253,108,62,218,7,
89692 50,63,93,15,183,1,204,143,215,195,237,224,115,35,246,80,253,208,28,200,253,
89693 156,7,34,7,50,63,105,1,195,1,204,143,219,64,114,32,104,67,246,248,28,136,
89694 26,16,28,200,253,228,7,34,7,50,63,133,15,229,1,204,143,225,192,114,224,115,
89695 35,248,144,28,72,28,200,254,52,7,46,6,132,63,143,129,203,129,161,1,204,143,
89696 230,64,114,224,115,35,250,88,28,200,24,64,24,0,254,158,7,50,6,16,6,2,63,
89697 173,1,204,129,161,15,235,224,115,32,97,0,104,67,252,88,29,40,24,64,24,0,
89698 255,30,7,74,6,16,6,2,63,201,1,208,129,137,143,243,64,116,160,104,67,252,
89699 248,29,40,24,64,26,16,255,148,63,244,7,50,63,231,1,212,129,204,143,250,64,
89700 113,224,115,35,254,208,29,72,26,16,255,190,7,82,6,132,7,50,63,249,1,212,
89701 129,204,253,128,64,8,192,8,223,96,48,2,48,2,79,216,20,0,140,0,153,246,7,
89702 128,35,0,35,0,36,253,130,96,8,192,8,192,9,159,96,176,2,152,2,167,216,52,0,
89703 166,0,169,246,39,2,162,2,163,125,138,64,168,128,166,191,98,176,42,32,41,
89704 223,216,180,10,156,10,141,246,47,2,162,2,158,128,
89705 };
89706 const duk_uint8_t duk_unicode_caseconv_lc[680] = {
89707 152,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
89708 235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32,
89709 0,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,9,208,85,184,80,19,
89710 240,19,248,12,62,16,62,0,32,124,96,124,64,48,249,64,249,0,129,243,129,243,
89711 1,3,233,3,232,1,135,218,7,216,4,15,196,15,192,8,31,152,31,144,16,63,80,63,
89712 64,32,126,224,126,192,16,253,208,251,128,33,252,129,247,32,131,251,3,250,0,
89713 135,246,135,221,129,15,244,15,240,2,31,234,31,122,4,63,240,62,240,8,127,
89714 232,125,240,17,11,1,11,129,2,75,98,77,3,69,128,5,134,11,203,31,128,143,193,
89715 127,144,255,160,154,140,4,0,4,4,192,9,144,9,152,48,19,144,19,161,0,41,64,
89716 41,101,192,94,64,94,129,128,193,0,193,130,1,160,1,161,6,3,102,3,104,8,7,44,
89717 7,48,72,14,240,14,248,144,31,32,31,48,64,63,0,63,37,0,136,128,136,196,129,
89718 35,1,35,133,3,112,3,113,4,7,176,7,178,48,17,128,17,132,136,36,80,36,89,176,
89719 76,16,76,32,224,154,0,154,44,7,128,7,128,101,143,80,15,80,176,31,89,31,81,
89720 8,88,206,88,208,12,178,0,178,5,145,103,89,103,96,42,100,10,100,18,244,208,
89721 20,208,35,169,200,169,200,195,211,153,83,153,159,167,121,167,122,5,78,253,
89722 78,254,22,158,66,158,68,21,60,181,60,184,170,123,74,123,80,67,0,211,1,64,2,
89723 1,172,1,173,4,3,136,3,140,12,7,20,7,24,16,31,184,31,192,34,199,34,199,48,
89724 65,128,195,128,196,2,1,184,1,185,5,79,84,4,204,8,0,192,101,128,154,65,1,29,
89725 129,30,2,16,199,45,39,5,251,240,23,128,15,240,24,16,37,48,24,96,37,64,24,
89726 224,29,208,24,240,37,144,25,0,37,176,25,16,25,32,25,48,38,0,25,64,38,48,25,
89727 112,38,128,25,128,25,144,25,208,39,32,25,240,39,80,26,112,26,128,26,224,40,
89728 128,27,112,41,32,31,16,31,48,31,96,25,80,31,112,27,240,34,0,25,224,35,162,
89729 198,80,35,208,25,160,35,226,198,96,36,48,24,0,36,64,40,144,36,80,40,192,55,
89730 96,55,112,55,240,63,48,56,96,58,192,56,192,60,192,60,240,61,112,63,64,59,
89731 128,63,144,63,32,76,0,76,241,233,224,13,241,251,193,251,49,252,193,252,49,
89732 254,193,254,81,255,193,255,50,18,96,60,146,18,160,6,178,18,176,14,82,19,34,
89733 20,226,24,50,24,66,198,2,198,18,198,32,38,178,198,49,215,210,198,64,39,210,
89734 198,208,37,18,198,224,39,18,198,240,37,2,199,0,37,34,207,34,207,58,119,209,
89735 215,154,120,186,120,202,120,208,38,90,122,176,37,202,122,192,38,26,122,208,
89736 38,202,123,0,41,234,123,16,40,122,123,32,41,218,123,58,181,48,32,38,16,3,
89737 72,24,56,
89738 };
89739
89740 #if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
89741 /*
89742  *  Automatically generated by extract_caseconv.py, do not edit!
89743  */
89744
89745 const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
89746 0,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,
89747 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
89748 53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,
89749 78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70,
89750 71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,123,124,125,
89751 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
89752 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
89753 162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
89754 180,924,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
89755 198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
89756 216,217,218,219,220,221,222,223,192,193,194,195,196,197,198,199,200,201,
89757 202,203,204,205,206,207,208,209,210,211,212,213,214,247,216,217,218,219,
89758 220,221,222,376,256,256,258,258,260,260,262,262,264,264,266,266,268,268,
89759 270,270,272,272,274,274,276,276,278,278,280,280,282,282,284,284,286,286,
89760 288,288,290,290,292,292,294,294,296,296,298,298,300,300,302,302,304,305,
89761 306,306,308,308,310,310,312,313,313,315,315,317,317,319,319,321,321,323,
89762 323,325,325,327,327,329,330,330,332,332,334,334,336,336,338,338,340,340,
89763 342,342,344,344,346,346,348,348,350,350,352,352,354,354,356,356,358,358,
89764 360,360,362,362,364,364,366,366,368,368,370,370,372,372,374,374,376,377,
89765 377,379,379,381,381,383,579,385,386,386,388,388,390,391,391,393,394,395,
89766 395,397,398,399,400,401,401,403,404,502,406,407,408,408,573,411,412,413,
89767 544,415,416,416,418,418,420,420,422,423,423,425,426,427,428,428,430,431,
89768 431,433,434,435,435,437,437,439,440,440,442,443,444,444,446,503,448,449,
89769 450,451,452,452,452,455,455,455,458,458,458,461,461,463,463,465,465,467,
89770 467,469,469,471,471,473,473,475,475,398,478,478,480,480,482,482,484,484,
89771 486,486,488,488,490,490,492,492,494,494,496,497,497,497,500,500,502,503,
89772 504,504,506,506,508,508,510,510,512,512,514,514,516,516,518,518,520,520,
89773 522,522,524,524,526,526,528,528,530,530,532,532,534,534,536,536,538,538,
89774 540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556,
89775 558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390,
89776 11391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375,
89777 11373,11376,385,390,597,393,394,600,399,602,400,42923L,605,606,607,403,
89778 42924L,610,404,612,42893L,42922L,615,407,406,42926L,11362,42925L,621,622,
89779 412,624,11374,413,627,628,415,630,631,632,633,634,635,636,11364,638,639,
89780 422,641,642,425,644,645,646,42929L,430,580,433,434,581,653,654,655,656,657,
89781 439,659,660,661,662,663,664,665,666,667,668,42930L,42928L,671,672,673,674,
89782 675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,
89783 693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,
89784 711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,
89785 729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,
89786 747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,
89787 765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,
89788 783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,
89789 801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,
89790 819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,
89791 921,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,
89792 855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,
89793 873,874,875,876,877,878,879,880,880,882,882,884,885,886,886,888,889,890,
89794 1021,1022,1023,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,
89795 909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,
89796 927,928,929,930,931,932,933,934,935,936,937,938,939,902,904,905,906,944,
89797 913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,
89798 931,932,933,934,935,936,937,938,939,908,910,911,975,914,920,978,979,980,
89799 934,928,975,984,984,986,986,988,988,990,990,992,992,994,994,996,996,998,
89800 998,1000,1000,1002,1002,1004,1004,1006,1006,922,929,1017,895,1012,917,1014,
89801 1015,1015,1017,1018,1018,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,
89802 1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,
89803 1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,
89804 1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1040,1041,1042,
89805 1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,
89806 1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,
89807 1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,
89808 1120,1120,1122,1122,1124,1124,1126,1126,1128,1128,1130,1130,1132,1132,1134,
89809 1134,1136,1136,1138,1138,1140,1140,1142,1142,1144,1144,1146,1146,1148,1148,
89810 1150,1150,1152,1152,1154,1155,1156,1157,1158,1159,1160,1161,1162,1162,1164,
89811 1164,1166,1166,1168,1168,1170,1170,1172,1172,1174,1174,1176,1176,1178,1178,
89812 1180,1180,1182,1182,1184,1184,1186,1186,1188,1188,1190,1190,1192,1192,1194,
89813 1194,1196,1196,1198,1198,1200,1200,1202,1202,1204,1204,1206,1206,1208,1208,
89814 1210,1210,1212,1212,1214,1214,1216,1217,1217,1219,1219,1221,1221,1223,1223,
89815 1225,1225,1227,1227,1229,1229,1216,1232,1232,1234,1234,1236,1236,1238,1238,
89816 1240,1240,1242,1242,1244,1244,1246,1246,1248,1248,1250,1250,1252,1252,1254,
89817 1254,1256,1256,1258,1258,1260,1260,1262,1262,1264,1264,1266,1266,1268,1268,
89818 1270,1270,1272,1272,1274,1274,1276,1276,1278,1278,1280,1280,1282,1282,1284,
89819 1284,1286,1286,1288,1288,1290,1290,1292,1292,1294,1294,1296,1296,1298,1298,
89820 1300,1300,1302,1302,1304,1304,1306,1306,1308,1308,1310,1310,1312,1312,1314,
89821 1314,1316,1316,1318,1318,1320,1320,1322,1322,1324,1324,1326,1326,1328,1329,
89822 1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,
89823 1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,
89824 1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,
89825 1375,1376,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,
89826 1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,
89827 1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1415,1416,1417,1418,1419,
89828 1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,
89829 1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,
89830 1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,
89831 1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,
89832 1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,
89833 1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,
89834 1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,
89835 1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,
89836 1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,
89837 1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,
89838 1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,
89839 1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,
89840 1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,
89841 1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,
89842 1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,
89843 1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,
89844 1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,
89845 1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,
89846 1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,
89847 1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,
89848 1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,
89849 1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,
89850 1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,
89851 1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,
89852 1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,
89853 1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,
89854 1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,
89855 1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,
89856 1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,
89857 1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,
89858 1870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,
89859 1885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,
89860 1900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,
89861 1915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,
89862 1930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,
89863 1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,
89864 1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,
89865 1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,
89866 1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,
89867 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,
89868 2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,
89869 2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,
89870 2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,
89871 2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,
89872 2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,
89873 2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,
89874 2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,
89875 2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,
89876 2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,
89877 2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,
89878 2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,
89879 2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,
89880 2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,
89881 2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,
89882 2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,
89883 2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,
89884 2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,
89885 2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,
89886 2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,
89887 2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,
89888 2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,
89889 2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,
89890 2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,
89891 2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,
89892 2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,
89893 2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,
89894 2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,
89895 2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,
89896 2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,
89897 2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,
89898 2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,
89899 2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,
89900 2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,
89901 2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,
89902 2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,
89903 2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,
89904 2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,
89905 2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,
89906 2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,
89907 2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,
89908 2620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,
89909 2635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,
89910 2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,
89911 2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,
89912 2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,
89913 2695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,
89914 2710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,
89915 2725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,
89916 2740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,
89917 2755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,
89918 2770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,
89919 2785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,
89920 2800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,
89921 2815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,
89922 2830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,
89923 2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,
89924 2860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,
89925 2875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,
89926 2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,
89927 2905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,
89928 2920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,
89929 2935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,
89930 2950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,
89931 2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,
89932 2980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,
89933 2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,
89934 3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,
89935 3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,
89936 3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,
89937 3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,
89938 3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,
89939 3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,
89940 3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,
89941 3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,
89942 3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,
89943 3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,
89944 3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,
89945 3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,
89946 3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,
89947 3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,
89948 3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,
89949 3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,
89950 3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,
89951 3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,
89952 3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,
89953 3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,
89954 3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,
89955 3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,
89956 3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,
89957 3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,
89958 3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,
89959 3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,
89960 3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,
89961 3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,
89962 3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,
89963 3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,
89964 3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,
89965 3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,
89966 3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,
89967 3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,
89968 3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,
89969 3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,
89970 3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,
89971 3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,
89972 3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,
89973 3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,
89974 3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,
89975 3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,
89976 3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,
89977 3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,
89978 3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,
89979 3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,
89980 3700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,
89981 3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,
89982 3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,
89983 3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,
89984 3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,
89985 3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,
89986 3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,
89987 3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,
89988 3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,
89989 3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,
89990 3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,
89991 3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,
89992 3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,
89993 3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,
89994 3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,
89995 3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,
89996 3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,
89997 3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,
89998 3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,
89999 3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,
90000 4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,
90001 4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,
90002 4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,
90003 4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,
90004 4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,
90005 4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,
90006 4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,
90007 4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,
90008 4120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,
90009 4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,
90010 4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,
90011 4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,
90012 4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,
90013 4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,
90014 4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,
90015 4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,
90016 4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,
90017 4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,
90018 4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,
90019 4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,
90020 4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,
90021 4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,
90022 4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,
90023 4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,
90024 4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,
90025 4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,
90026 4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,
90027 4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,
90028 4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,
90029 4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,
90030 4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,
90031 4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,
90032 4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,
90033 4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,
90034 4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,
90035 4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,
90036 4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,
90037 4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,
90038 4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,
90039 4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,
90040 4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,
90041 4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,
90042 4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,
90043 4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,
90044 4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,
90045 4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,
90046 4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,
90047 4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,
90048 4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,
90049 4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,
90050 4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,
90051 4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,
90052 4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,
90053 4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,
90054 4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,
90055 4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,
90056 4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,
90057 4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,
90058 4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,
90059 4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,
90060 4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,
90061 4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,
90062 4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,
90063 4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,
90064 4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,
90065 4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,
90066 4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,
90067 5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,
90068 5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,
90069 5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,
90070 5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,
90071 5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,
90072 5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,
90073 5095,5096,5097,5098,5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,
90074 5110,5111,5104,5105,5106,5107,5108,5109,5118,5119,5120,5121,5122,5123,5124,
90075 5125,5126,5127,5128,5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,
90076 5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,
90077 5155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,
90078 5170,5171,5172,5173,5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,
90079 5185,5186,5187,5188,5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,
90080 5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,
90081 5215,5216,5217,5218,5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,
90082 5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,
90083 5245,5246,5247,5248,5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,
90084 5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,
90085 5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,
90086 5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,
90087 5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,
90088 5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,
90089 5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,
90090 5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,
90091 5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,
90092 5380,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,
90093 5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409,
90094 5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,
90095 5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,
90096 5440,5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,
90097 5455,5456,5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,
90098 5470,5471,5472,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,
90099 5485,5486,5487,5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,
90100 5500,5501,5502,5503,5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,
90101 5515,5516,5517,5518,5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,
90102 5530,5531,5532,5533,5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,
90103 5545,5546,5547,5548,5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,
90104 5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,
90105 5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,
90106 5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,
90107 5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,
90108 5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,
90109 5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,
90110 5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,
90111 5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,
90112 5680,5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,
90113 5695,5696,5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,
90114 5710,5711,5712,5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,
90115 5725,5726,5727,5728,5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,
90116 5740,5741,5742,5743,5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,
90117 5755,5756,5757,5758,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,
90118 5770,5771,5772,5773,5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,
90119 5785,5786,5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,
90120 5800,5801,5802,5803,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,
90121 5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,
90122 5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,
90123 5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,
90124 5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,
90125 5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,
90126 5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,
90127 5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,
90128 5920,5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,
90129 5935,5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,
90130 5950,5951,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,
90131 5965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,
90132 5980,5981,5982,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,
90133 5995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,
90134 6010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,
90135 6025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,
90136 6040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,
90137 6055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,
90138 6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,
90139 6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,
90140 6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,
90141 6115,6116,6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,
90142 6130,6131,6132,6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,
90143 6145,6146,6147,6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,
90144 6160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,
90145 6175,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,
90146 6190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,
90147 6205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,
90148 6220,6221,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234,
90149 6235,6236,6237,6238,6239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249,
90150 6250,6251,6252,6253,6254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264,
90151 6265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275,6276,6277,6278,6279,
90152 6280,6281,6282,6283,6284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,
90153 6295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309,
90154 6310,6311,6312,6313,6314,6315,6316,6317,6318,6319,6320,6321,6322,6323,6324,
90155 6325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,
90156 6340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,
90157 6355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,
90158 6370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384,
90159 6385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,
90160 6400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414,
90161 6415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429,
90162 6430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6444,
90163 6445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,
90164 6460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474,
90165 6475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,
90166 6490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,
90167 6505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,
90168 6520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,
90169 6535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,
90170 6550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,
90171 6565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,
90172 6580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,
90173 6595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,
90174 6610,6611,6612,6613,6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,
90175 6625,6626,6627,6628,6629,6630,6631,6632,6633,6634,6635,6636,6637,6638,6639,
90176 6640,6641,6642,6643,6644,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,
90177 6655,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,
90178 6670,6671,6672,6673,6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,
90179 6685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,
90180 6700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,
90181 6715,6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,
90182 6730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,
90183 6745,6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,
90184 6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,
90185 6775,6776,6777,6778,6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6789,
90186 6790,6791,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,
90187 6805,6806,6807,6808,6809,6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,
90188 6820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,
90189 6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,
90190 6850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,
90191 6865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879,
90192 6880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,
90193 6895,6896,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,
90194 6910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,
90195 6925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,
90196 6940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,
90197 6955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969,
90198 6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,
90199 6985,6986,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999,
90200 7000,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014,
90201 7015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,
90202 7030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042,7043,7044,
90203 7045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,
90204 7060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,
90205 7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,
90206 7090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,
90207 7105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,
90208 7120,7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,
90209 7135,7136,7137,7138,7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,
90210 7150,7151,7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,
90211 7165,7166,7167,7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,
90212 7180,7181,7182,7183,7184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,
90213 7195,7196,7197,7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,
90214 7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,
90215 7225,7226,7227,7228,7229,7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,
90216 7240,7241,7242,7243,7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,
90217 7255,7256,7257,7258,7259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269,
90218 7270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,
90219 7285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,1042,1044,1054,1057,
90220 1058,1058,1066,1122,42570L,7305,7306,7307,7308,7309,7310,7311,7312,7313,
90221 7314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327,7328,
90222 7329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343,
90223 7344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,7358,
90224 7359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372,7373,
90225 7374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387,7388,
90226 7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402,7403,
90227 7404,7405,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415,7416,7417,7418,
90228 7419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,
90229 7434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447,7448,
90230 7449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462,7463,
90231 7464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,7475,7476,7477,7478,
90232 7479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492,7493,
90233 7494,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507,7508,
90234 7509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,7522,7523,
90235 7524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537,7538,
90236 7539,7540,7541,7542,7543,7544,42877L,7546,7547,7548,11363,7550,7551,7552,
90237 7553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567,
90238 7568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,
90239 7583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,
90240 7598,7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,
90241 7613,7614,7615,7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,
90242 7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,
90243 7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,
90244 7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,
90245 7673,7674,7675,7676,7677,7678,7679,7680,7680,7682,7682,7684,7684,7686,7686,
90246 7688,7688,7690,7690,7692,7692,7694,7694,7696,7696,7698,7698,7700,7700,7702,
90247 7702,7704,7704,7706,7706,7708,7708,7710,7710,7712,7712,7714,7714,7716,7716,
90248 7718,7718,7720,7720,7722,7722,7724,7724,7726,7726,7728,7728,7730,7730,7732,
90249 7732,7734,7734,7736,7736,7738,7738,7740,7740,7742,7742,7744,7744,7746,7746,
90250 7748,7748,7750,7750,7752,7752,7754,7754,7756,7756,7758,7758,7760,7760,7762,
90251 7762,7764,7764,7766,7766,7768,7768,7770,7770,7772,7772,7774,7774,7776,7776,
90252 7778,7778,7780,7780,7782,7782,7784,7784,7786,7786,7788,7788,7790,7790,7792,
90253 7792,7794,7794,7796,7796,7798,7798,7800,7800,7802,7802,7804,7804,7806,7806,
90254 7808,7808,7810,7810,7812,7812,7814,7814,7816,7816,7818,7818,7820,7820,7822,
90255 7822,7824,7824,7826,7826,7828,7828,7830,7831,7832,7833,7834,7776,7836,7837,
90256 7838,7839,7840,7840,7842,7842,7844,7844,7846,7846,7848,7848,7850,7850,7852,
90257 7852,7854,7854,7856,7856,7858,7858,7860,7860,7862,7862,7864,7864,7866,7866,
90258 7868,7868,7870,7870,7872,7872,7874,7874,7876,7876,7878,7878,7880,7880,7882,
90259 7882,7884,7884,7886,7886,7888,7888,7890,7890,7892,7892,7894,7894,7896,7896,
90260 7898,7898,7900,7900,7902,7902,7904,7904,7906,7906,7908,7908,7910,7910,7912,
90261 7912,7914,7914,7916,7916,7918,7918,7920,7920,7922,7922,7924,7924,7926,7926,
90262 7928,7928,7930,7930,7932,7932,7934,7934,7944,7945,7946,7947,7948,7949,7950,
90263 7951,7944,7945,7946,7947,7948,7949,7950,7951,7960,7961,7962,7963,7964,7965,
90264 7958,7959,7960,7961,7962,7963,7964,7965,7966,7967,7976,7977,7978,7979,7980,
90265 7981,7982,7983,7976,7977,7978,7979,7980,7981,7982,7983,7992,7993,7994,7995,
90266 7996,7997,7998,7999,7992,7993,7994,7995,7996,7997,7998,7999,8008,8009,8010,
90267 8011,8012,8013,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015,8016,8025,
90268 8018,8027,8020,8029,8022,8031,8024,8025,8026,8027,8028,8029,8030,8031,8040,
90269 8041,8042,8043,8044,8045,8046,8047,8040,8041,8042,8043,8044,8045,8046,8047,
90270 8122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171,8186,8187,8062,
90271 8063,8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,
90272 8078,8079,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,
90273 8093,8094,8095,8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,
90274 8108,8109,8110,8111,8120,8121,8114,8115,8116,8117,8118,8119,8120,8121,8122,
90275 8123,8124,8125,921,8127,8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,
90276 8138,8139,8140,8141,8142,8143,8152,8153,8146,8147,8148,8149,8150,8151,8152,
90277 8153,8154,8155,8156,8157,8158,8159,8168,8169,8162,8163,8164,8172,8166,8167,
90278 8168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,8182,
90279 8183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197,
90280 8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,
90281 8213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,
90282 8228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,
90283 8243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,
90284 8258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,
90285 8273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,
90286 8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,
90287 8303,8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,
90288 8318,8319,8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,
90289 8333,8334,8335,8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,
90290 8348,8349,8350,8351,8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,
90291 8363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373,8374,8375,8376,8377,
90292 8378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,
90293 8393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8405,8406,8407,
90294 8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421,8422,
90295 8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437,
90296 8438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,
90297 8453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,
90298 8468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,
90299 8483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,
90300 8498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,
90301 8513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524,8525,8498,8527,
90302 8528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8540,8541,8542,
90303 8543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,
90304 8558,8559,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,
90305 8557,8558,8559,8576,8577,8578,8579,8579,8581,8582,8583,8584,8585,8586,8587,
90306 8588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599,8600,8601,8602,
90307 8603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613,8614,8615,8616,8617,
90308 8618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629,8630,8631,8632,
90309 8633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,8645,8646,8647,
90310 8648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,8660,8661,8662,
90311 8663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677,
90312 8678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,
90313 8693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,
90314 8708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,
90315 8723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,
90316 8738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749,8750,8751,8752,
90317 8753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,8764,8765,8766,8767,
90318 8768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,8780,8781,8782,
90319 8783,8784,8785,8786,8787,8788,8789,8790,8791,8792,8793,8794,8795,8796,8797,
90320 8798,8799,8800,8801,8802,8803,8804,8805,8806,8807,8808,8809,8810,8811,8812,
90321 8813,8814,8815,8816,8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,
90322 8828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839,8840,8841,8842,
90323 8843,8844,8845,8846,8847,8848,8849,8850,8851,8852,8853,8854,8855,8856,8857,
90324 8858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869,8870,8871,8872,
90325 8873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,8885,8886,8887,
90326 8888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899,8900,8901,8902,
90327 8903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914,8915,8916,8917,
90328 8918,8919,8920,8921,8922,8923,8924,8925,8926,8927,8928,8929,8930,8931,8932,
90329 8933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,8944,8945,8946,8947,
90330 8948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959,8960,8961,8962,
90331 8963,8964,8965,8966,8967,8968,8969,8970,8971,8972,8973,8974,8975,8976,8977,
90332 8978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,
90333 8993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007,
90334 9008,9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,9022,
90335 9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,
90336 9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,
90337 9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,9065,9066,9067,
90338 9068,9069,9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,
90339 9083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,
90340 9098,9099,9100,9101,9102,9103,9104,9105,9106,9107,9108,9109,9110,9111,9112,
90341 9113,9114,9115,9116,9117,9118,9119,9120,9121,9122,9123,9124,9125,9126,9127,
90342 9128,9129,9130,9131,9132,9133,9134,9135,9136,9137,9138,9139,9140,9141,9142,
90343 9143,9144,9145,9146,9147,9148,9149,9150,9151,9152,9153,9154,9155,9156,9157,
90344 9158,9159,9160,9161,9162,9163,9164,9165,9166,9167,9168,9169,9170,9171,9172,
90345 9173,9174,9175,9176,9177,9178,9179,9180,9181,9182,9183,9184,9185,9186,9187,
90346 9188,9189,9190,9191,9192,9193,9194,9195,9196,9197,9198,9199,9200,9201,9202,
90347 9203,9204,9205,9206,9207,9208,9209,9210,9211,9212,9213,9214,9215,9216,9217,
90348 9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,
90349 9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,
90350 9248,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258,9259,9260,9261,9262,
90351 9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9274,9275,9276,9277,
90352 9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289,9290,9291,9292,
90353 9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9304,9305,9306,9307,
90354 9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,
90355 9323,9324,9325,9326,9327,9328,9329,9330,9331,9332,9333,9334,9335,9336,9337,
90356 9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9352,
90357 9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,
90358 9368,9369,9370,9371,9372,9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,
90359 9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,
90360 9398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,
90361 9413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,9398,9399,9400,9401,
90362 9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,
90363 9417,9418,9419,9420,9421,9422,9423,9450,9451,9452,9453,9454,9455,9456,9457,
90364 9458,9459,9460,9461,9462,9463,9464,9465,9466,9467,9468,9469,9470,9471,9472,
90365 9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,
90366 9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,
90367 9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,
90368 9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,
90369 9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,
90370 9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,
90371 9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,
90372 9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588,9589,9590,9591,9592,
90373 9593,9594,9595,9596,9597,9598,9599,9600,9601,9602,9603,9604,9605,9606,9607,
90374 9608,9609,9610,9611,9612,9613,9614,9615,9616,9617,9618,9619,9620,9621,9622,
90375 9623,9624,9625,9626,9627,9628,9629,9630,9631,9632,9633,9634,9635,9636,9637,
90376 9638,9639,9640,9641,9642,9643,9644,9645,9646,9647,9648,9649,9650,9651,9652,
90377 9653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9663,9664,9665,9666,9667,
90378 9668,9669,9670,9671,9672,9673,9674,9675,9676,9677,9678,9679,9680,9681,9682,
90379 9683,9684,9685,9686,9687,9688,9689,9690,9691,9692,9693,9694,9695,9696,9697,
90380 9698,9699,9700,9701,9702,9703,9704,9705,9706,9707,9708,9709,9710,9711,9712,
90381 9713,9714,9715,9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,
90382 9728,9729,9730,9731,9732,9733,9734,9735,9736,9737,9738,9739,9740,9741,9742,
90383 9743,9744,9745,9746,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9757,
90384 9758,9759,9760,9761,9762,9763,9764,9765,9766,9767,9768,9769,9770,9771,9772,
90385 9773,9774,9775,9776,9777,9778,9779,9780,9781,9782,9783,9784,9785,9786,9787,
90386 9788,9789,9790,9791,9792,9793,9794,9795,9796,9797,9798,9799,9800,9801,9802,
90387 9803,9804,9805,9806,9807,9808,9809,9810,9811,9812,9813,9814,9815,9816,9817,
90388 9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,
90389 9833,9834,9835,9836,9837,9838,9839,9840,9841,9842,9843,9844,9845,9846,9847,
90390 9848,9849,9850,9851,9852,9853,9854,9855,9856,9857,9858,9859,9860,9861,9862,
90391 9863,9864,9865,9866,9867,9868,9869,9870,9871,9872,9873,9874,9875,9876,9877,
90392 9878,9879,9880,9881,9882,9883,9884,9885,9886,9887,9888,9889,9890,9891,9892,
90393 9893,9894,9895,9896,9897,9898,9899,9900,9901,9902,9903,9904,9905,9906,9907,
90394 9908,9909,9910,9911,9912,9913,9914,9915,9916,9917,9918,9919,9920,9921,9922,
90395 9923,9924,9925,9926,9927,9928,9929,9930,9931,9932,9933,9934,9935,9936,9937,
90396 9938,9939,9940,9941,9942,9943,9944,9945,9946,9947,9948,9949,9950,9951,9952,
90397 9953,9954,9955,9956,9957,9958,9959,9960,9961,9962,9963,9964,9965,9966,9967,
90398 9968,9969,9970,9971,9972,9973,9974,9975,9976,9977,9978,9979,9980,9981,9982,
90399 9983,9984,9985,9986,9987,9988,9989,9990,9991,9992,9993,9994,9995,9996,9997,
90400 9998,9999,10000,10001,10002,10003,10004,10005,10006,10007,10008,10009,
90401 10010,10011,10012,10013,10014,10015,10016,10017,10018,10019,10020,10021,
90402 10022,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033,
90403 10034,10035,10036,10037,10038,10039,10040,10041,10042,10043,10044,10045,
90404 10046,10047,10048,10049,10050,10051,10052,10053,10054,10055,10056,10057,
90405 10058,10059,10060,10061,10062,10063,10064,10065,10066,10067,10068,10069,
90406 10070,10071,10072,10073,10074,10075,10076,10077,10078,10079,10080,10081,
90407 10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092,10093,
90408 10094,10095,10096,10097,10098,10099,10100,10101,10102,10103,10104,10105,
90409 10106,10107,10108,10109,10110,10111,10112,10113,10114,10115,10116,10117,
90410 10118,10119,10120,10121,10122,10123,10124,10125,10126,10127,10128,10129,
90411 10130,10131,10132,10133,10134,10135,10136,10137,10138,10139,10140,10141,
90412 10142,10143,10144,10145,10146,10147,10148,10149,10150,10151,10152,10153,
90413 10154,10155,10156,10157,10158,10159,10160,10161,10162,10163,10164,10165,
90414 10166,10167,10168,10169,10170,10171,10172,10173,10174,10175,10176,10177,
90415 10178,10179,10180,10181,10182,10183,10184,10185,10186,10187,10188,10189,
90416 10190,10191,10192,10193,10194,10195,10196,10197,10198,10199,10200,10201,
90417 10202,10203,10204,10205,10206,10207,10208,10209,10210,10211,10212,10213,
90418 10214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225,
90419 10226,10227,10228,10229,10230,10231,10232,10233,10234,10235,10236,10237,
90420 10238,10239,10240,10241,10242,10243,10244,10245,10246,10247,10248,10249,
90421 10250,10251,10252,10253,10254,10255,10256,10257,10258,10259,10260,10261,
90422 10262,10263,10264,10265,10266,10267,10268,10269,10270,10271,10272,10273,
90423 10274,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,10285,
90424 10286,10287,10288,10289,10290,10291,10292,10293,10294,10295,10296,10297,
90425 10298,10299,10300,10301,10302,10303,10304,10305,10306,10307,10308,10309,
90426 10310,10311,10312,10313,10314,10315,10316,10317,10318,10319,10320,10321,
90427 10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333,
90428 10334,10335,10336,10337,10338,10339,10340,10341,10342,10343,10344,10345,
90429 10346,10347,10348,10349,10350,10351,10352,10353,10354,10355,10356,10357,
90430 10358,10359,10360,10361,10362,10363,10364,10365,10366,10367,10368,10369,
90431 10370,10371,10372,10373,10374,10375,10376,10377,10378,10379,10380,10381,
90432 10382,10383,10384,10385,10386,10387,10388,10389,10390,10391,10392,10393,
90433 10394,10395,10396,10397,10398,10399,10400,10401,10402,10403,10404,10405,
90434 10406,10407,10408,10409,10410,10411,10412,10413,10414,10415,10416,10417,
90435 10418,10419,10420,10421,10422,10423,10424,10425,10426,10427,10428,10429,
90436 10430,10431,10432,10433,10434,10435,10436,10437,10438,10439,10440,10441,
90437 10442,10443,10444,10445,10446,10447,10448,10449,10450,10451,10452,10453,
90438 10454,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10465,
90439 10466,10467,10468,10469,10470,10471,10472,10473,10474,10475,10476,10477,
90440 10478,10479,10480,10481,10482,10483,10484,10485,10486,10487,10488,10489,
90441 10490,10491,10492,10493,10494,10495,10496,10497,10498,10499,10500,10501,
90442 10502,10503,10504,10505,10506,10507,10508,10509,10510,10511,10512,10513,
90443 10514,10515,10516,10517,10518,10519,10520,10521,10522,10523,10524,10525,
90444 10526,10527,10528,10529,10530,10531,10532,10533,10534,10535,10536,10537,
90445 10538,10539,10540,10541,10542,10543,10544,10545,10546,10547,10548,10549,
90446 10550,10551,10552,10553,10554,10555,10556,10557,10558,10559,10560,10561,
90447 10562,10563,10564,10565,10566,10567,10568,10569,10570,10571,10572,10573,
90448 10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585,
90449 10586,10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597,
90450 10598,10599,10600,10601,10602,10603,10604,10605,10606,10607,10608,10609,
90451 10610,10611,10612,10613,10614,10615,10616,10617,10618,10619,10620,10621,
90452 10622,10623,10624,10625,10626,10627,10628,10629,10630,10631,10632,10633,
90453 10634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,
90454 10646,10647,10648,10649,10650,10651,10652,10653,10654,10655,10656,10657,
90455 10658,10659,10660,10661,10662,10663,10664,10665,10666,10667,10668,10669,
90456 10670,10671,10672,10673,10674,10675,10676,10677,10678,10679,10680,10681,
90457 10682,10683,10684,10685,10686,10687,10688,10689,10690,10691,10692,10693,
90458 10694,10695,10696,10697,10698,10699,10700,10701,10702,10703,10704,10705,
90459 10706,10707,10708,10709,10710,10711,10712,10713,10714,10715,10716,10717,
90460 10718,10719,10720,10721,10722,10723,10724,10725,10726,10727,10728,10729,
90461 10730,10731,10732,10733,10734,10735,10736,10737,10738,10739,10740,10741,
90462 10742,10743,10744,10745,10746,10747,10748,10749,10750,10751,10752,10753,
90463 10754,10755,10756,10757,10758,10759,10760,10761,10762,10763,10764,10765,
90464 10766,10767,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777,
90465 10778,10779,10780,10781,10782,10783,10784,10785,10786,10787,10788,10789,
90466 10790,10791,10792,10793,10794,10795,10796,10797,10798,10799,10800,10801,
90467 10802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812,10813,
90468 10814,10815,10816,10817,10818,10819,10820,10821,10822,10823,10824,10825,
90469 10826,10827,10828,10829,10830,10831,10832,10833,10834,10835,10836,10837,
90470 10838,10839,10840,10841,10842,10843,10844,10845,10846,10847,10848,10849,
90471 10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860,10861,
90472 10862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,
90473 10874,10875,10876,10877,10878,10879,10880,10881,10882,10883,10884,10885,
90474 10886,10887,10888,10889,10890,10891,10892,10893,10894,10895,10896,10897,
90475 10898,10899,10900,10901,10902,10903,10904,10905,10906,10907,10908,10909,
90476 10910,10911,10912,10913,10914,10915,10916,10917,10918,10919,10920,10921,
90477 10922,10923,10924,10925,10926,10927,10928,10929,10930,10931,10932,10933,
90478 10934,10935,10936,10937,10938,10939,10940,10941,10942,10943,10944,10945,
90479 10946,10947,10948,10949,10950,10951,10952,10953,10954,10955,10956,10957,
90480 10958,10959,10960,10961,10962,10963,10964,10965,10966,10967,10968,10969,
90481 10970,10971,10972,10973,10974,10975,10976,10977,10978,10979,10980,10981,
90482 10982,10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10993,
90483 10994,10995,10996,10997,10998,10999,11000,11001,11002,11003,11004,11005,
90484 11006,11007,11008,11009,11010,11011,11012,11013,11014,11015,11016,11017,
90485 11018,11019,11020,11021,11022,11023,11024,11025,11026,11027,11028,11029,
90486 11030,11031,11032,11033,11034,11035,11036,11037,11038,11039,11040,11041,
90487 11042,11043,11044,11045,11046,11047,11048,11049,11050,11051,11052,11053,
90488 11054,11055,11056,11057,11058,11059,11060,11061,11062,11063,11064,11065,
90489 11066,11067,11068,11069,11070,11071,11072,11073,11074,11075,11076,11077,
90490 11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088,11089,
90491 11090,11091,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,
90492 11102,11103,11104,11105,11106,11107,11108,11109,11110,11111,11112,11113,
90493 11114,11115,11116,11117,11118,11119,11120,11121,11122,11123,11124,11125,
90494 11126,11127,11128,11129,11130,11131,11132,11133,11134,11135,11136,11137,
90495 11138,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,
90496 11150,11151,11152,11153,11154,11155,11156,11157,11158,11159,11160,11161,
90497 11162,11163,11164,11165,11166,11167,11168,11169,11170,11171,11172,11173,
90498 11174,11175,11176,11177,11178,11179,11180,11181,11182,11183,11184,11185,
90499 11186,11187,11188,11189,11190,11191,11192,11193,11194,11195,11196,11197,
90500 11198,11199,11200,11201,11202,11203,11204,11205,11206,11207,11208,11209,
90501 11210,11211,11212,11213,11214,11215,11216,11217,11218,11219,11220,11221,
90502 11222,11223,11224,11225,11226,11227,11228,11229,11230,11231,11232,11233,
90503 11234,11235,11236,11237,11238,11239,11240,11241,11242,11243,11244,11245,
90504 11246,11247,11248,11249,11250,11251,11252,11253,11254,11255,11256,11257,
90505 11258,11259,11260,11261,11262,11263,11264,11265,11266,11267,11268,11269,
90506 11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281,
90507 11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,
90508 11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,
90509 11306,11307,11308,11309,11310,11311,11264,11265,11266,11267,11268,11269,
90510 11270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281,
90511 11282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,
90512 11294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,
90513 11306,11307,11308,11309,11310,11359,11360,11360,11362,11363,11364,570,574,
90514 11367,11367,11369,11369,11371,11371,11373,11374,11375,11376,11377,11378,
90515 11378,11380,11381,11381,11383,11384,11385,11386,11387,11388,11389,11390,
90516 11391,11392,11392,11394,11394,11396,11396,11398,11398,11400,11400,11402,
90517 11402,11404,11404,11406,11406,11408,11408,11410,11410,11412,11412,11414,
90518 11414,11416,11416,11418,11418,11420,11420,11422,11422,11424,11424,11426,
90519 11426,11428,11428,11430,11430,11432,11432,11434,11434,11436,11436,11438,
90520 11438,11440,11440,11442,11442,11444,11444,11446,11446,11448,11448,11450,
90521 11450,11452,11452,11454,11454,11456,11456,11458,11458,11460,11460,11462,
90522 11462,11464,11464,11466,11466,11468,11468,11470,11470,11472,11472,11474,
90523 11474,11476,11476,11478,11478,11480,11480,11482,11482,11484,11484,11486,
90524 11486,11488,11488,11490,11490,11492,11493,11494,11495,11496,11497,11498,
90525 11499,11499,11501,11501,11503,11504,11505,11506,11506,11508,11509,11510,
90526 11511,11512,11513,11514,11515,11516,11517,11518,11519,4256,4257,4258,4259,
90527 4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,
90528 4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,
90529 4290,4291,4292,4293,11558,4295,11560,11561,11562,11563,11564,4301,11566,
90530 11567,11568,11569,11570,11571,11572,11573,11574,11575,11576,11577,11578,
90531 11579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,11590,
90532 11591,11592,11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,
90533 11603,11604,11605,11606,11607,11608,11609,11610,11611,11612,11613,11614,
90534 11615,11616,11617,11618,11619,11620,11621,11622,11623,11624,11625,11626,
90535 11627,11628,11629,11630,11631,11632,11633,11634,11635,11636,11637,11638,
90536 11639,11640,11641,11642,11643,11644,11645,11646,11647,11648,11649,11650,
90537 11651,11652,11653,11654,11655,11656,11657,11658,11659,11660,11661,11662,
90538 11663,11664,11665,11666,11667,11668,11669,11670,11671,11672,11673,11674,
90539 11675,11676,11677,11678,11679,11680,11681,11682,11683,11684,11685,11686,
90540 11687,11688,11689,11690,11691,11692,11693,11694,11695,11696,11697,11698,
90541 11699,11700,11701,11702,11703,11704,11705,11706,11707,11708,11709,11710,
90542 11711,11712,11713,11714,11715,11716,11717,11718,11719,11720,11721,11722,
90543 11723,11724,11725,11726,11727,11728,11729,11730,11731,11732,11733,11734,
90544 11735,11736,11737,11738,11739,11740,11741,11742,11743,11744,11745,11746,
90545 11747,11748,11749,11750,11751,11752,11753,11754,11755,11756,11757,11758,
90546 11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,
90547 11771,11772,11773,11774,11775,11776,11777,11778,11779,11780,11781,11782,
90548 11783,11784,11785,11786,11787,11788,11789,11790,11791,11792,11793,11794,
90549 11795,11796,11797,11798,11799,11800,11801,11802,11803,11804,11805,11806,
90550 11807,11808,11809,11810,11811,11812,11813,11814,11815,11816,11817,11818,
90551 11819,11820,11821,11822,11823,11824,11825,11826,11827,11828,11829,11830,
90552 11831,11832,11833,11834,11835,11836,11837,11838,11839,11840,11841,11842,
90553 11843,11844,11845,11846,11847,11848,11849,11850,11851,11852,11853,11854,
90554 11855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866,
90555 11867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878,
90556 11879,11880,11881,11882,11883,11884,11885,11886,11887,11888,11889,11890,
90557 11891,11892,11893,11894,11895,11896,11897,11898,11899,11900,11901,11902,
90558 11903,11904,11905,11906,11907,11908,11909,11910,11911,11912,11913,11914,
90559 11915,11916,11917,11918,11919,11920,11921,11922,11923,11924,11925,11926,
90560 11927,11928,11929,11930,11931,11932,11933,11934,11935,11936,11937,11938,
90561 11939,11940,11941,11942,11943,11944,11945,11946,11947,11948,11949,11950,
90562 11951,11952,11953,11954,11955,11956,11957,11958,11959,11960,11961,11962,
90563 11963,11964,11965,11966,11967,11968,11969,11970,11971,11972,11973,11974,
90564 11975,11976,11977,11978,11979,11980,11981,11982,11983,11984,11985,11986,
90565 11987,11988,11989,11990,11991,11992,11993,11994,11995,11996,11997,11998,
90566 11999,12000,12001,12002,12003,12004,12005,12006,12007,12008,12009,12010,
90567 12011,12012,12013,12014,12015,12016,12017,12018,12019,12020,12021,12022,
90568 12023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034,
90569 12035,12036,12037,12038,12039,12040,12041,12042,12043,12044,12045,12046,
90570 12047,12048,12049,12050,12051,12052,12053,12054,12055,12056,12057,12058,
90571 12059,12060,12061,12062,12063,12064,12065,12066,12067,12068,12069,12070,
90572 12071,12072,12073,12074,12075,12076,12077,12078,12079,12080,12081,12082,
90573 12083,12084,12085,12086,12087,12088,12089,12090,12091,12092,12093,12094,
90574 12095,12096,12097,12098,12099,12100,12101,12102,12103,12104,12105,12106,
90575 12107,12108,12109,12110,12111,12112,12113,12114,12115,12116,12117,12118,
90576 12119,12120,12121,12122,12123,12124,12125,12126,12127,12128,12129,12130,
90577 12131,12132,12133,12134,12135,12136,12137,12138,12139,12140,12141,12142,
90578 12143,12144,12145,12146,12147,12148,12149,12150,12151,12152,12153,12154,
90579 12155,12156,12157,12158,12159,12160,12161,12162,12163,12164,12165,12166,
90580 12167,12168,12169,12170,12171,12172,12173,12174,12175,12176,12177,12178,
90581 12179,12180,12181,12182,12183,12184,12185,12186,12187,12188,12189,12190,
90582 12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,
90583 12203,12204,12205,12206,12207,12208,12209,12210,12211,12212,12213,12214,
90584 12215,12216,12217,12218,12219,12220,12221,12222,12223,12224,12225,12226,
90585 12227,12228,12229,12230,12231,12232,12233,12234,12235,12236,12237,12238,
90586 12239,12240,12241,12242,12243,12244,12245,12246,12247,12248,12249,12250,
90587 12251,12252,12253,12254,12255,12256,12257,12258,12259,12260,12261,12262,
90588 12263,12264,12265,12266,12267,12268,12269,12270,12271,12272,12273,12274,
90589 12275,12276,12277,12278,12279,12280,12281,12282,12283,12284,12285,12286,
90590 12287,12288,12289,12290,12291,12292,12293,12294,12295,12296,12297,12298,
90591 12299,12300,12301,12302,12303,12304,12305,12306,12307,12308,12309,12310,
90592 12311,12312,12313,12314,12315,12316,12317,12318,12319,12320,12321,12322,
90593 12323,12324,12325,12326,12327,12328,12329,12330,12331,12332,12333,12334,
90594 12335,12336,12337,12338,12339,12340,12341,12342,12343,12344,12345,12346,
90595 12347,12348,12349,12350,12351,12352,12353,12354,12355,12356,12357,12358,
90596 12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,
90597 12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,
90598 12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,
90599 12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,
90600 12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,
90601 12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,
90602 12431,12432,12433,12434,12435,12436,12437,12438,12439,12440,12441,12442,
90603 12443,12444,12445,12446,12447,12448,12449,12450,12451,12452,12453,12454,
90604 12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,
90605 12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,
90606 12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,
90607 12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,
90608 12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,
90609 12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,
90610 12527,12528,12529,12530,12531,12532,12533,12534,12535,12536,12537,12538,
90611 12539,12540,12541,12542,12543,12544,12545,12546,12547,12548,12549,12550,
90612 12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,
90613 12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,
90614 12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,12586,
90615 12587,12588,12589,12590,12591,12592,12593,12594,12595,12596,12597,12598,
90616 12599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,
90617 12611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622,
90618 12623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634,
90619 12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,
90620 12647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,
90621 12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,
90622 12671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682,
90623 12683,12684,12685,12686,12687,12688,12689,12690,12691,12692,12693,12694,
90624 12695,12696,12697,12698,12699,12700,12701,12702,12703,12704,12705,12706,
90625 12707,12708,12709,12710,12711,12712,12713,12714,12715,12716,12717,12718,
90626 12719,12720,12721,12722,12723,12724,12725,12726,12727,12728,12729,12730,
90627 12731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742,
90628 12743,12744,12745,12746,12747,12748,12749,12750,12751,12752,12753,12754,
90629 12755,12756,12757,12758,12759,12760,12761,12762,12763,12764,12765,12766,
90630 12767,12768,12769,12770,12771,12772,12773,12774,12775,12776,12777,12778,
90631 12779,12780,12781,12782,12783,12784,12785,12786,12787,12788,12789,12790,
90632 12791,12792,12793,12794,12795,12796,12797,12798,12799,12800,12801,12802,
90633 12803,12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,
90634 12815,12816,12817,12818,12819,12820,12821,12822,12823,12824,12825,12826,
90635 12827,12828,12829,12830,12831,12832,12833,12834,12835,12836,12837,12838,
90636 12839,12840,12841,12842,12843,12844,12845,12846,12847,12848,12849,12850,
90637 12851,12852,12853,12854,12855,12856,12857,12858,12859,12860,12861,12862,
90638 12863,12864,12865,12866,12867,12868,12869,12870,12871,12872,12873,12874,
90639 12875,12876,12877,12878,12879,12880,12881,12882,12883,12884,12885,12886,
90640 12887,12888,12889,12890,12891,12892,12893,12894,12895,12896,12897,12898,
90641 12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,
90642 12911,12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,
90643 12923,12924,12925,12926,12927,12928,12929,12930,12931,12932,12933,12934,
90644 12935,12936,12937,12938,12939,12940,12941,12942,12943,12944,12945,12946,
90645 12947,12948,12949,12950,12951,12952,12953,12954,12955,12956,12957,12958,
90646 12959,12960,12961,12962,12963,12964,12965,12966,12967,12968,12969,12970,
90647 12971,12972,12973,12974,12975,12976,12977,12978,12979,12980,12981,12982,
90648 12983,12984,12985,12986,12987,12988,12989,12990,12991,12992,12993,12994,
90649 12995,12996,12997,12998,12999,13000,13001,13002,13003,13004,13005,13006,
90650 13007,13008,13009,13010,13011,13012,13013,13014,13015,13016,13017,13018,
90651 13019,13020,13021,13022,13023,13024,13025,13026,13027,13028,13029,13030,
90652 13031,13032,13033,13034,13035,13036,13037,13038,13039,13040,13041,13042,
90653 13043,13044,13045,13046,13047,13048,13049,13050,13051,13052,13053,13054,
90654 13055,13056,13057,13058,13059,13060,13061,13062,13063,13064,13065,13066,
90655 13067,13068,13069,13070,13071,13072,13073,13074,13075,13076,13077,13078,
90656 13079,13080,13081,13082,13083,13084,13085,13086,13087,13088,13089,13090,
90657 13091,13092,13093,13094,13095,13096,13097,13098,13099,13100,13101,13102,
90658 13103,13104,13105,13106,13107,13108,13109,13110,13111,13112,13113,13114,
90659 13115,13116,13117,13118,13119,13120,13121,13122,13123,13124,13125,13126,
90660 13127,13128,13129,13130,13131,13132,13133,13134,13135,13136,13137,13138,
90661 13139,13140,13141,13142,13143,13144,13145,13146,13147,13148,13149,13150,
90662 13151,13152,13153,13154,13155,13156,13157,13158,13159,13160,13161,13162,
90663 13163,13164,13165,13166,13167,13168,13169,13170,13171,13172,13173,13174,
90664 13175,13176,13177,13178,13179,13180,13181,13182,13183,13184,13185,13186,
90665 13187,13188,13189,13190,13191,13192,13193,13194,13195,13196,13197,13198,
90666 13199,13200,13201,13202,13203,13204,13205,13206,13207,13208,13209,13210,
90667 13211,13212,13213,13214,13215,13216,13217,13218,13219,13220,13221,13222,
90668 13223,13224,13225,13226,13227,13228,13229,13230,13231,13232,13233,13234,
90669 13235,13236,13237,13238,13239,13240,13241,13242,13243,13244,13245,13246,
90670 13247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258,
90671 13259,13260,13261,13262,13263,13264,13265,13266,13267,13268,13269,13270,
90672 13271,13272,13273,13274,13275,13276,13277,13278,13279,13280,13281,13282,
90673 13283,13284,13285,13286,13287,13288,13289,13290,13291,13292,13293,13294,
90674 13295,13296,13297,13298,13299,13300,13301,13302,13303,13304,13305,13306,
90675 13307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318,
90676 13319,13320,13321,13322,13323,13324,13325,13326,13327,13328,13329,13330,
90677 13331,13332,13333,13334,13335,13336,13337,13338,13339,13340,13341,13342,
90678 13343,13344,13345,13346,13347,13348,13349,13350,13351,13352,13353,13354,
90679 13355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,
90680 13367,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,
90681 13379,13380,13381,13382,13383,13384,13385,13386,13387,13388,13389,13390,
90682 13391,13392,13393,13394,13395,13396,13397,13398,13399,13400,13401,13402,
90683 13403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414,
90684 13415,13416,13417,13418,13419,13420,13421,13422,13423,13424,13425,13426,
90685 13427,13428,13429,13430,13431,13432,13433,13434,13435,13436,13437,13438,
90686 13439,13440,13441,13442,13443,13444,13445,13446,13447,13448,13449,13450,
90687 13451,13452,13453,13454,13455,13456,13457,13458,13459,13460,13461,13462,
90688 13463,13464,13465,13466,13467,13468,13469,13470,13471,13472,13473,13474,
90689 13475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,
90690 13487,13488,13489,13490,13491,13492,13493,13494,13495,13496,13497,13498,
90691 13499,13500,13501,13502,13503,13504,13505,13506,13507,13508,13509,13510,
90692 13511,13512,13513,13514,13515,13516,13517,13518,13519,13520,13521,13522,
90693 13523,13524,13525,13526,13527,13528,13529,13530,13531,13532,13533,13534,
90694 13535,13536,13537,13538,13539,13540,13541,13542,13543,13544,13545,13546,
90695 13547,13548,13549,13550,13551,13552,13553,13554,13555,13556,13557,13558,
90696 13559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570,
90697 13571,13572,13573,13574,13575,13576,13577,13578,13579,13580,13581,13582,
90698 13583,13584,13585,13586,13587,13588,13589,13590,13591,13592,13593,13594,
90699 13595,13596,13597,13598,13599,13600,13601,13602,13603,13604,13605,13606,
90700 13607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618,
90701 13619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,
90702 13631,13632,13633,13634,13635,13636,13637,13638,13639,13640,13641,13642,
90703 13643,13644,13645,13646,13647,13648,13649,13650,13651,13652,13653,13654,
90704 13655,13656,13657,13658,13659,13660,13661,13662,13663,13664,13665,13666,
90705 13667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13678,
90706 13679,13680,13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,
90707 13691,13692,13693,13694,13695,13696,13697,13698,13699,13700,13701,13702,
90708 13703,13704,13705,13706,13707,13708,13709,13710,13711,13712,13713,13714,
90709 13715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,
90710 13727,13728,13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,
90711 13739,13740,13741,13742,13743,13744,13745,13746,13747,13748,13749,13750,
90712 13751,13752,13753,13754,13755,13756,13757,13758,13759,13760,13761,13762,
90713 13763,13764,13765,13766,13767,13768,13769,13770,13771,13772,13773,13774,
90714 13775,13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,
90715 13787,13788,13789,13790,13791,13792,13793,13794,13795,13796,13797,13798,
90716 13799,13800,13801,13802,13803,13804,13805,13806,13807,13808,13809,13810,
90717 13811,13812,13813,13814,13815,13816,13817,13818,13819,13820,13821,13822,
90718 13823,13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,
90719 13835,13836,13837,13838,13839,13840,13841,13842,13843,13844,13845,13846,
90720 13847,13848,13849,13850,13851,13852,13853,13854,13855,13856,13857,13858,
90721 13859,13860,13861,13862,13863,13864,13865,13866,13867,13868,13869,13870,
90722 13871,13872,13873,13874,13875,13876,13877,13878,13879,13880,13881,13882,
90723 13883,13884,13885,13886,13887,13888,13889,13890,13891,13892,13893,13894,
90724 13895,13896,13897,13898,13899,13900,13901,13902,13903,13904,13905,13906,
90725 13907,13908,13909,13910,13911,13912,13913,13914,13915,13916,13917,13918,
90726 13919,13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,
90727 13931,13932,13933,13934,13935,13936,13937,13938,13939,13940,13941,13942,
90728 13943,13944,13945,13946,13947,13948,13949,13950,13951,13952,13953,13954,
90729 13955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,
90730 13967,13968,13969,13970,13971,13972,13973,13974,13975,13976,13977,13978,
90731 13979,13980,13981,13982,13983,13984,13985,13986,13987,13988,13989,13990,
90732 13991,13992,13993,13994,13995,13996,13997,13998,13999,14000,14001,14002,
90733 14003,14004,14005,14006,14007,14008,14009,14010,14011,14012,14013,14014,
90734 14015,14016,14017,14018,14019,14020,14021,14022,14023,14024,14025,14026,
90735 14027,14028,14029,14030,14031,14032,14033,14034,14035,14036,14037,14038,
90736 14039,14040,14041,14042,14043,14044,14045,14046,14047,14048,14049,14050,
90737 14051,14052,14053,14054,14055,14056,14057,14058,14059,14060,14061,14062,
90738 14063,14064,14065,14066,14067,14068,14069,14070,14071,14072,14073,14074,
90739 14075,14076,14077,14078,14079,14080,14081,14082,14083,14084,14085,14086,
90740 14087,14088,14089,14090,14091,14092,14093,14094,14095,14096,14097,14098,
90741 14099,14100,14101,14102,14103,14104,14105,14106,14107,14108,14109,14110,
90742 14111,14112,14113,14114,14115,14116,14117,14118,14119,14120,14121,14122,
90743 14123,14124,14125,14126,14127,14128,14129,14130,14131,14132,14133,14134,
90744 14135,14136,14137,14138,14139,14140,14141,14142,14143,14144,14145,14146,
90745 14147,14148,14149,14150,14151,14152,14153,14154,14155,14156,14157,14158,
90746 14159,14160,14161,14162,14163,14164,14165,14166,14167,14168,14169,14170,
90747 14171,14172,14173,14174,14175,14176,14177,14178,14179,14180,14181,14182,
90748 14183,14184,14185,14186,14187,14188,14189,14190,14191,14192,14193,14194,
90749 14195,14196,14197,14198,14199,14200,14201,14202,14203,14204,14205,14206,
90750 14207,14208,14209,14210,14211,14212,14213,14214,14215,14216,14217,14218,
90751 14219,14220,14221,14222,14223,14224,14225,14226,14227,14228,14229,14230,
90752 14231,14232,14233,14234,14235,14236,14237,14238,14239,14240,14241,14242,
90753 14243,14244,14245,14246,14247,14248,14249,14250,14251,14252,14253,14254,
90754 14255,14256,14257,14258,14259,14260,14261,14262,14263,14264,14265,14266,
90755 14267,14268,14269,14270,14271,14272,14273,14274,14275,14276,14277,14278,
90756 14279,14280,14281,14282,14283,14284,14285,14286,14287,14288,14289,14290,
90757 14291,14292,14293,14294,14295,14296,14297,14298,14299,14300,14301,14302,
90758 14303,14304,14305,14306,14307,14308,14309,14310,14311,14312,14313,14314,
90759 14315,14316,14317,14318,14319,14320,14321,14322,14323,14324,14325,14326,
90760 14327,14328,14329,14330,14331,14332,14333,14334,14335,14336,14337,14338,
90761 14339,14340,14341,14342,14343,14344,14345,14346,14347,14348,14349,14350,
90762 14351,14352,14353,14354,14355,14356,14357,14358,14359,14360,14361,14362,
90763 14363,14364,14365,14366,14367,14368,14369,14370,14371,14372,14373,14374,
90764 14375,14376,14377,14378,14379,14380,14381,14382,14383,14384,14385,14386,
90765 14387,14388,14389,14390,14391,14392,14393,14394,14395,14396,14397,14398,
90766 14399,14400,14401,14402,14403,14404,14405,14406,14407,14408,14409,14410,
90767 14411,14412,14413,14414,14415,14416,14417,14418,14419,14420,14421,14422,
90768 14423,14424,14425,14426,14427,14428,14429,14430,14431,14432,14433,14434,
90769 14435,14436,14437,14438,14439,14440,14441,14442,14443,14444,14445,14446,
90770 14447,14448,14449,14450,14451,14452,14453,14454,14455,14456,14457,14458,
90771 14459,14460,14461,14462,14463,14464,14465,14466,14467,14468,14469,14470,
90772 14471,14472,14473,14474,14475,14476,14477,14478,14479,14480,14481,14482,
90773 14483,14484,14485,14486,14487,14488,14489,14490,14491,14492,14493,14494,
90774 14495,14496,14497,14498,14499,14500,14501,14502,14503,14504,14505,14506,
90775 14507,14508,14509,14510,14511,14512,14513,14514,14515,14516,14517,14518,
90776 14519,14520,14521,14522,14523,14524,14525,14526,14527,14528,14529,14530,
90777 14531,14532,14533,14534,14535,14536,14537,14538,14539,14540,14541,14542,
90778 14543,14544,14545,14546,14547,14548,14549,14550,14551,14552,14553,14554,
90779 14555,14556,14557,14558,14559,14560,14561,14562,14563,14564,14565,14566,
90780 14567,14568,14569,14570,14571,14572,14573,14574,14575,14576,14577,14578,
90781 14579,14580,14581,14582,14583,14584,14585,14586,14587,14588,14589,14590,
90782 14591,14592,14593,14594,14595,14596,14597,14598,14599,14600,14601,14602,
90783 14603,14604,14605,14606,14607,14608,14609,14610,14611,14612,14613,14614,
90784 14615,14616,14617,14618,14619,14620,14621,14622,14623,14624,14625,14626,
90785 14627,14628,14629,14630,14631,14632,14633,14634,14635,14636,14637,14638,
90786 14639,14640,14641,14642,14643,14644,14645,14646,14647,14648,14649,14650,
90787 14651,14652,14653,14654,14655,14656,14657,14658,14659,14660,14661,14662,
90788 14663,14664,14665,14666,14667,14668,14669,14670,14671,14672,14673,14674,
90789 14675,14676,14677,14678,14679,14680,14681,14682,14683,14684,14685,14686,
90790 14687,14688,14689,14690,14691,14692,14693,14694,14695,14696,14697,14698,
90791 14699,14700,14701,14702,14703,14704,14705,14706,14707,14708,14709,14710,
90792 14711,14712,14713,14714,14715,14716,14717,14718,14719,14720,14721,14722,
90793 14723,14724,14725,14726,14727,14728,14729,14730,14731,14732,14733,14734,
90794 14735,14736,14737,14738,14739,14740,14741,14742,14743,14744,14745,14746,
90795 14747,14748,14749,14750,14751,14752,14753,14754,14755,14756,14757,14758,
90796 14759,14760,14761,14762,14763,14764,14765,14766,14767,14768,14769,14770,
90797 14771,14772,14773,14774,14775,14776,14777,14778,14779,14780,14781,14782,
90798 14783,14784,14785,14786,14787,14788,14789,14790,14791,14792,14793,14794,
90799 14795,14796,14797,14798,14799,14800,14801,14802,14803,14804,14805,14806,
90800 14807,14808,14809,14810,14811,14812,14813,14814,14815,14816,14817,14818,
90801 14819,14820,14821,14822,14823,14824,14825,14826,14827,14828,14829,14830,
90802 14831,14832,14833,14834,14835,14836,14837,14838,14839,14840,14841,14842,
90803 14843,14844,14845,14846,14847,14848,14849,14850,14851,14852,14853,14854,
90804 14855,14856,14857,14858,14859,14860,14861,14862,14863,14864,14865,14866,
90805 14867,14868,14869,14870,14871,14872,14873,14874,14875,14876,14877,14878,
90806 14879,14880,14881,14882,14883,14884,14885,14886,14887,14888,14889,14890,
90807 14891,14892,14893,14894,14895,14896,14897,14898,14899,14900,14901,14902,
90808 14903,14904,14905,14906,14907,14908,14909,14910,14911,14912,14913,14914,
90809 14915,14916,14917,14918,14919,14920,14921,14922,14923,14924,14925,14926,
90810 14927,14928,14929,14930,14931,14932,14933,14934,14935,14936,14937,14938,
90811 14939,14940,14941,14942,14943,14944,14945,14946,14947,14948,14949,14950,
90812 14951,14952,14953,14954,14955,14956,14957,14958,14959,14960,14961,14962,
90813 14963,14964,14965,14966,14967,14968,14969,14970,14971,14972,14973,14974,
90814 14975,14976,14977,14978,14979,14980,14981,14982,14983,14984,14985,14986,
90815 14987,14988,14989,14990,14991,14992,14993,14994,14995,14996,14997,14998,
90816 14999,15000,15001,15002,15003,15004,15005,15006,15007,15008,15009,15010,
90817 15011,15012,15013,15014,15015,15016,15017,15018,15019,15020,15021,15022,
90818 15023,15024,15025,15026,15027,15028,15029,15030,15031,15032,15033,15034,
90819 15035,15036,15037,15038,15039,15040,15041,15042,15043,15044,15045,15046,
90820 15047,15048,15049,15050,15051,15052,15053,15054,15055,15056,15057,15058,
90821 15059,15060,15061,15062,15063,15064,15065,15066,15067,15068,15069,15070,
90822 15071,15072,15073,15074,15075,15076,15077,15078,15079,15080,15081,15082,
90823 15083,15084,15085,15086,15087,15088,15089,15090,15091,15092,15093,15094,
90824 15095,15096,15097,15098,15099,15100,15101,15102,15103,15104,15105,15106,
90825 15107,15108,15109,15110,15111,15112,15113,15114,15115,15116,15117,15118,
90826 15119,15120,15121,15122,15123,15124,15125,15126,15127,15128,15129,15130,
90827 15131,15132,15133,15134,15135,15136,15137,15138,15139,15140,15141,15142,
90828 15143,15144,15145,15146,15147,15148,15149,15150,15151,15152,15153,15154,
90829 15155,15156,15157,15158,15159,15160,15161,15162,15163,15164,15165,15166,
90830 15167,15168,15169,15170,15171,15172,15173,15174,15175,15176,15177,15178,
90831 15179,15180,15181,15182,15183,15184,15185,15186,15187,15188,15189,15190,
90832 15191,15192,15193,15194,15195,15196,15197,15198,15199,15200,15201,15202,
90833 15203,15204,15205,15206,15207,15208,15209,15210,15211,15212,15213,15214,
90834 15215,15216,15217,15218,15219,15220,15221,15222,15223,15224,15225,15226,
90835 15227,15228,15229,15230,15231,15232,15233,15234,15235,15236,15237,15238,
90836 15239,15240,15241,15242,15243,15244,15245,15246,15247,15248,15249,15250,
90837 15251,15252,15253,15254,15255,15256,15257,15258,15259,15260,15261,15262,
90838 15263,15264,15265,15266,15267,15268,15269,15270,15271,15272,15273,15274,
90839 15275,15276,15277,15278,15279,15280,15281,15282,15283,15284,15285,15286,
90840 15287,15288,15289,15290,15291,15292,15293,15294,15295,15296,15297,15298,
90841 15299,15300,15301,15302,15303,15304,15305,15306,15307,15308,15309,15310,
90842 15311,15312,15313,15314,15315,15316,15317,15318,15319,15320,15321,15322,
90843 15323,15324,15325,15326,15327,15328,15329,15330,15331,15332,15333,15334,
90844 15335,15336,15337,15338,15339,15340,15341,15342,15343,15344,15345,15346,
90845 15347,15348,15349,15350,15351,15352,15353,15354,15355,15356,15357,15358,
90846 15359,15360,15361,15362,15363,15364,15365,15366,15367,15368,15369,15370,
90847 15371,15372,15373,15374,15375,15376,15377,15378,15379,15380,15381,15382,
90848 15383,15384,15385,15386,15387,15388,15389,15390,15391,15392,15393,15394,
90849 15395,15396,15397,15398,15399,15400,15401,15402,15403,15404,15405,15406,
90850 15407,15408,15409,15410,15411,15412,15413,15414,15415,15416,15417,15418,
90851 15419,15420,15421,15422,15423,15424,15425,15426,15427,15428,15429,15430,
90852 15431,15432,15433,15434,15435,15436,15437,15438,15439,15440,15441,15442,
90853 15443,15444,15445,15446,15447,15448,15449,15450,15451,15452,15453,15454,
90854 15455,15456,15457,15458,15459,15460,15461,15462,15463,15464,15465,15466,
90855 15467,15468,15469,15470,15471,15472,15473,15474,15475,15476,15477,15478,
90856 15479,15480,15481,15482,15483,15484,15485,15486,15487,15488,15489,15490,
90857 15491,15492,15493,15494,15495,15496,15497,15498,15499,15500,15501,15502,
90858 15503,15504,15505,15506,15507,15508,15509,15510,15511,15512,15513,15514,
90859 15515,15516,15517,15518,15519,15520,15521,15522,15523,15524,15525,15526,
90860 15527,15528,15529,15530,15531,15532,15533,15534,15535,15536,15537,15538,
90861 15539,15540,15541,15542,15543,15544,15545,15546,15547,15548,15549,15550,
90862 15551,15552,15553,15554,15555,15556,15557,15558,15559,15560,15561,15562,
90863 15563,15564,15565,15566,15567,15568,15569,15570,15571,15572,15573,15574,
90864 15575,15576,15577,15578,15579,15580,15581,15582,15583,15584,15585,15586,
90865 15587,15588,15589,15590,15591,15592,15593,15594,15595,15596,15597,15598,
90866 15599,15600,15601,15602,15603,15604,15605,15606,15607,15608,15609,15610,
90867 15611,15612,15613,15614,15615,15616,15617,15618,15619,15620,15621,15622,
90868 15623,15624,15625,15626,15627,15628,15629,15630,15631,15632,15633,15634,
90869 15635,15636,15637,15638,15639,15640,15641,15642,15643,15644,15645,15646,
90870 15647,15648,15649,15650,15651,15652,15653,15654,15655,15656,15657,15658,
90871 15659,15660,15661,15662,15663,15664,15665,15666,15667,15668,15669,15670,
90872 15671,15672,15673,15674,15675,15676,15677,15678,15679,15680,15681,15682,
90873 15683,15684,15685,15686,15687,15688,15689,15690,15691,15692,15693,15694,
90874 15695,15696,15697,15698,15699,15700,15701,15702,15703,15704,15705,15706,
90875 15707,15708,15709,15710,15711,15712,15713,15714,15715,15716,15717,15718,
90876 15719,15720,15721,15722,15723,15724,15725,15726,15727,15728,15729,15730,
90877 15731,15732,15733,15734,15735,15736,15737,15738,15739,15740,15741,15742,
90878 15743,15744,15745,15746,15747,15748,15749,15750,15751,15752,15753,15754,
90879 15755,15756,15757,15758,15759,15760,15761,15762,15763,15764,15765,15766,
90880 15767,15768,15769,15770,15771,15772,15773,15774,15775,15776,15777,15778,
90881 15779,15780,15781,15782,15783,15784,15785,15786,15787,15788,15789,15790,
90882 15791,15792,15793,15794,15795,15796,15797,15798,15799,15800,15801,15802,
90883 15803,15804,15805,15806,15807,15808,15809,15810,15811,15812,15813,15814,
90884 15815,15816,15817,15818,15819,15820,15821,15822,15823,15824,15825,15826,
90885 15827,15828,15829,15830,15831,15832,15833,15834,15835,15836,15837,15838,
90886 15839,15840,15841,15842,15843,15844,15845,15846,15847,15848,15849,15850,
90887 15851,15852,15853,15854,15855,15856,15857,15858,15859,15860,15861,15862,
90888 15863,15864,15865,15866,15867,15868,15869,15870,15871,15872,15873,15874,
90889 15875,15876,15877,15878,15879,15880,15881,15882,15883,15884,15885,15886,
90890 15887,15888,15889,15890,15891,15892,15893,15894,15895,15896,15897,15898,
90891 15899,15900,15901,15902,15903,15904,15905,15906,15907,15908,15909,15910,
90892 15911,15912,15913,15914,15915,15916,15917,15918,15919,15920,15921,15922,
90893 15923,15924,15925,15926,15927,15928,15929,15930,15931,15932,15933,15934,
90894 15935,15936,15937,15938,15939,15940,15941,15942,15943,15944,15945,15946,
90895 15947,15948,15949,15950,15951,15952,15953,15954,15955,15956,15957,15958,
90896 15959,15960,15961,15962,15963,15964,15965,15966,15967,15968,15969,15970,
90897 15971,15972,15973,15974,15975,15976,15977,15978,15979,15980,15981,15982,
90898 15983,15984,15985,15986,15987,15988,15989,15990,15991,15992,15993,15994,
90899 15995,15996,15997,15998,15999,16000,16001,16002,16003,16004,16005,16006,
90900 16007,16008,16009,16010,16011,16012,16013,16014,16015,16016,16017,16018,
90901 16019,16020,16021,16022,16023,16024,16025,16026,16027,16028,16029,16030,
90902 16031,16032,16033,16034,16035,16036,16037,16038,16039,16040,16041,16042,
90903 16043,16044,16045,16046,16047,16048,16049,16050,16051,16052,16053,16054,
90904 16055,16056,16057,16058,16059,16060,16061,16062,16063,16064,16065,16066,
90905 16067,16068,16069,16070,16071,16072,16073,16074,16075,16076,16077,16078,
90906 16079,16080,16081,16082,16083,16084,16085,16086,16087,16088,16089,16090,
90907 16091,16092,16093,16094,16095,16096,16097,16098,16099,16100,16101,16102,
90908 16103,16104,16105,16106,16107,16108,16109,16110,16111,16112,16113,16114,
90909 16115,16116,16117,16118,16119,16120,16121,16122,16123,16124,16125,16126,
90910 16127,16128,16129,16130,16131,16132,16133,16134,16135,16136,16137,16138,
90911 16139,16140,16141,16142,16143,16144,16145,16146,16147,16148,16149,16150,
90912 16151,16152,16153,16154,16155,16156,16157,16158,16159,16160,16161,16162,
90913 16163,16164,16165,16166,16167,16168,16169,16170,16171,16172,16173,16174,
90914 16175,16176,16177,16178,16179,16180,16181,16182,16183,16184,16185,16186,
90915 16187,16188,16189,16190,16191,16192,16193,16194,16195,16196,16197,16198,
90916 16199,16200,16201,16202,16203,16204,16205,16206,16207,16208,16209,16210,
90917 16211,16212,16213,16214,16215,16216,16217,16218,16219,16220,16221,16222,
90918 16223,16224,16225,16226,16227,16228,16229,16230,16231,16232,16233,16234,
90919 16235,16236,16237,16238,16239,16240,16241,16242,16243,16244,16245,16246,
90920 16247,16248,16249,16250,16251,16252,16253,16254,16255,16256,16257,16258,
90921 16259,16260,16261,16262,16263,16264,16265,16266,16267,16268,16269,16270,
90922 16271,16272,16273,16274,16275,16276,16277,16278,16279,16280,16281,16282,
90923 16283,16284,16285,16286,16287,16288,16289,16290,16291,16292,16293,16294,
90924 16295,16296,16297,16298,16299,16300,16301,16302,16303,16304,16305,16306,
90925 16307,16308,16309,16310,16311,16312,16313,16314,16315,16316,16317,16318,
90926 16319,16320,16321,16322,16323,16324,16325,16326,16327,16328,16329,16330,
90927 16331,16332,16333,16334,16335,16336,16337,16338,16339,16340,16341,16342,
90928 16343,16344,16345,16346,16347,16348,16349,16350,16351,16352,16353,16354,
90929 16355,16356,16357,16358,16359,16360,16361,16362,16363,16364,16365,16366,
90930 16367,16368,16369,16370,16371,16372,16373,16374,16375,16376,16377,16378,
90931 16379,16380,16381,16382,16383,16384,16385,16386,16387,16388,16389,16390,
90932 16391,16392,16393,16394,16395,16396,16397,16398,16399,16400,16401,16402,
90933 16403,16404,16405,16406,16407,16408,16409,16410,16411,16412,16413,16414,
90934 16415,16416,16417,16418,16419,16420,16421,16422,16423,16424,16425,16426,
90935 16427,16428,16429,16430,16431,16432,16433,16434,16435,16436,16437,16438,
90936 16439,16440,16441,16442,16443,16444,16445,16446,16447,16448,16449,16450,
90937 16451,16452,16453,16454,16455,16456,16457,16458,16459,16460,16461,16462,
90938 16463,16464,16465,16466,16467,16468,16469,16470,16471,16472,16473,16474,
90939 16475,16476,16477,16478,16479,16480,16481,16482,16483,16484,16485,16486,
90940 16487,16488,16489,16490,16491,16492,16493,16494,16495,16496,16497,16498,
90941 16499,16500,16501,16502,16503,16504,16505,16506,16507,16508,16509,16510,
90942 16511,16512,16513,16514,16515,16516,16517,16518,16519,16520,16521,16522,
90943 16523,16524,16525,16526,16527,16528,16529,16530,16531,16532,16533,16534,
90944 16535,16536,16537,16538,16539,16540,16541,16542,16543,16544,16545,16546,
90945 16547,16548,16549,16550,16551,16552,16553,16554,16555,16556,16557,16558,
90946 16559,16560,16561,16562,16563,16564,16565,16566,16567,16568,16569,16570,
90947 16571,16572,16573,16574,16575,16576,16577,16578,16579,16580,16581,16582,
90948 16583,16584,16585,16586,16587,16588,16589,16590,16591,16592,16593,16594,
90949 16595,16596,16597,16598,16599,16600,16601,16602,16603,16604,16605,16606,
90950 16607,16608,16609,16610,16611,16612,16613,16614,16615,16616,16617,16618,
90951 16619,16620,16621,16622,16623,16624,16625,16626,16627,16628,16629,16630,
90952 16631,16632,16633,16634,16635,16636,16637,16638,16639,16640,16641,16642,
90953 16643,16644,16645,16646,16647,16648,16649,16650,16651,16652,16653,16654,
90954 16655,16656,16657,16658,16659,16660,16661,16662,16663,16664,16665,16666,
90955 16667,16668,16669,16670,16671,16672,16673,16674,16675,16676,16677,16678,
90956 16679,16680,16681,16682,16683,16684,16685,16686,16687,16688,16689,16690,
90957 16691,16692,16693,16694,16695,16696,16697,16698,16699,16700,16701,16702,
90958 16703,16704,16705,16706,16707,16708,16709,16710,16711,16712,16713,16714,
90959 16715,16716,16717,16718,16719,16720,16721,16722,16723,16724,16725,16726,
90960 16727,16728,16729,16730,16731,16732,16733,16734,16735,16736,16737,16738,
90961 16739,16740,16741,16742,16743,16744,16745,16746,16747,16748,16749,16750,
90962 16751,16752,16753,16754,16755,16756,16757,16758,16759,16760,16761,16762,
90963 16763,16764,16765,16766,16767,16768,16769,16770,16771,16772,16773,16774,
90964 16775,16776,16777,16778,16779,16780,16781,16782,16783,16784,16785,16786,
90965 16787,16788,16789,16790,16791,16792,16793,16794,16795,16796,16797,16798,
90966 16799,16800,16801,16802,16803,16804,16805,16806,16807,16808,16809,16810,
90967 16811,16812,16813,16814,16815,16816,16817,16818,16819,16820,16821,16822,
90968 16823,16824,16825,16826,16827,16828,16829,16830,16831,16832,16833,16834,
90969 16835,16836,16837,16838,16839,16840,16841,16842,16843,16844,16845,16846,
90970 16847,16848,16849,16850,16851,16852,16853,16854,16855,16856,16857,16858,
90971 16859,16860,16861,16862,16863,16864,16865,16866,16867,16868,16869,16870,
90972 16871,16872,16873,16874,16875,16876,16877,16878,16879,16880,16881,16882,
90973 16883,16884,16885,16886,16887,16888,16889,16890,16891,16892,16893,16894,
90974 16895,16896,16897,16898,16899,16900,16901,16902,16903,16904,16905,16906,
90975 16907,16908,16909,16910,16911,16912,16913,16914,16915,16916,16917,16918,
90976 16919,16920,16921,16922,16923,16924,16925,16926,16927,16928,16929,16930,
90977 16931,16932,16933,16934,16935,16936,16937,16938,16939,16940,16941,16942,
90978 16943,16944,16945,16946,16947,16948,16949,16950,16951,16952,16953,16954,
90979 16955,16956,16957,16958,16959,16960,16961,16962,16963,16964,16965,16966,
90980 16967,16968,16969,16970,16971,16972,16973,16974,16975,16976,16977,16978,
90981 16979,16980,16981,16982,16983,16984,16985,16986,16987,16988,16989,16990,
90982 16991,16992,16993,16994,16995,16996,16997,16998,16999,17000,17001,17002,
90983 17003,17004,17005,17006,17007,17008,17009,17010,17011,17012,17013,17014,
90984 17015,17016,17017,17018,17019,17020,17021,17022,17023,17024,17025,17026,
90985 17027,17028,17029,17030,17031,17032,17033,17034,17035,17036,17037,17038,
90986 17039,17040,17041,17042,17043,17044,17045,17046,17047,17048,17049,17050,
90987 17051,17052,17053,17054,17055,17056,17057,17058,17059,17060,17061,17062,
90988 17063,17064,17065,17066,17067,17068,17069,17070,17071,17072,17073,17074,
90989 17075,17076,17077,17078,17079,17080,17081,17082,17083,17084,17085,17086,
90990 17087,17088,17089,17090,17091,17092,17093,17094,17095,17096,17097,17098,
90991 17099,17100,17101,17102,17103,17104,17105,17106,17107,17108,17109,17110,
90992 17111,17112,17113,17114,17115,17116,17117,17118,17119,17120,17121,17122,
90993 17123,17124,17125,17126,17127,17128,17129,17130,17131,17132,17133,17134,
90994 17135,17136,17137,17138,17139,17140,17141,17142,17143,17144,17145,17146,
90995 17147,17148,17149,17150,17151,17152,17153,17154,17155,17156,17157,17158,
90996 17159,17160,17161,17162,17163,17164,17165,17166,17167,17168,17169,17170,
90997 17171,17172,17173,17174,17175,17176,17177,17178,17179,17180,17181,17182,
90998 17183,17184,17185,17186,17187,17188,17189,17190,17191,17192,17193,17194,
90999 17195,17196,17197,17198,17199,17200,17201,17202,17203,17204,17205,17206,
91000 17207,17208,17209,17210,17211,17212,17213,17214,17215,17216,17217,17218,
91001 17219,17220,17221,17222,17223,17224,17225,17226,17227,17228,17229,17230,
91002 17231,17232,17233,17234,17235,17236,17237,17238,17239,17240,17241,17242,
91003 17243,17244,17245,17246,17247,17248,17249,17250,17251,17252,17253,17254,
91004 17255,17256,17257,17258,17259,17260,17261,17262,17263,17264,17265,17266,
91005 17267,17268,17269,17270,17271,17272,17273,17274,17275,17276,17277,17278,
91006 17279,17280,17281,17282,17283,17284,17285,17286,17287,17288,17289,17290,
91007 17291,17292,17293,17294,17295,17296,17297,17298,17299,17300,17301,17302,
91008 17303,17304,17305,17306,17307,17308,17309,17310,17311,17312,17313,17314,
91009 17315,17316,17317,17318,17319,17320,17321,17322,17323,17324,17325,17326,
91010 17327,17328,17329,17330,17331,17332,17333,17334,17335,17336,17337,17338,
91011 17339,17340,17341,17342,17343,17344,17345,17346,17347,17348,17349,17350,
91012 17351,17352,17353,17354,17355,17356,17357,17358,17359,17360,17361,17362,
91013 17363,17364,17365,17366,17367,17368,17369,17370,17371,17372,17373,17374,
91014 17375,17376,17377,17378,17379,17380,17381,17382,17383,17384,17385,17386,
91015 17387,17388,17389,17390,17391,17392,17393,17394,17395,17396,17397,17398,
91016 17399,17400,17401,17402,17403,17404,17405,17406,17407,17408,17409,17410,
91017 17411,17412,17413,17414,17415,17416,17417,17418,17419,17420,17421,17422,
91018 17423,17424,17425,17426,17427,17428,17429,17430,17431,17432,17433,17434,
91019 17435,17436,17437,17438,17439,17440,17441,17442,17443,17444,17445,17446,
91020 17447,17448,17449,17450,17451,17452,17453,17454,17455,17456,17457,17458,
91021 17459,17460,17461,17462,17463,17464,17465,17466,17467,17468,17469,17470,
91022 17471,17472,17473,17474,17475,17476,17477,17478,17479,17480,17481,17482,
91023 17483,17484,17485,17486,17487,17488,17489,17490,17491,17492,17493,17494,
91024 17495,17496,17497,17498,17499,17500,17501,17502,17503,17504,17505,17506,
91025 17507,17508,17509,17510,17511,17512,17513,17514,17515,17516,17517,17518,
91026 17519,17520,17521,17522,17523,17524,17525,17526,17527,17528,17529,17530,
91027 17531,17532,17533,17534,17535,17536,17537,17538,17539,17540,17541,17542,
91028 17543,17544,17545,17546,17547,17548,17549,17550,17551,17552,17553,17554,
91029 17555,17556,17557,17558,17559,17560,17561,17562,17563,17564,17565,17566,
91030 17567,17568,17569,17570,17571,17572,17573,17574,17575,17576,17577,17578,
91031 17579,17580,17581,17582,17583,17584,17585,17586,17587,17588,17589,17590,
91032 17591,17592,17593,17594,17595,17596,17597,17598,17599,17600,17601,17602,
91033 17603,17604,17605,17606,17607,17608,17609,17610,17611,17612,17613,17614,
91034 17615,17616,17617,17618,17619,17620,17621,17622,17623,17624,17625,17626,
91035 17627,17628,17629,17630,17631,17632,17633,17634,17635,17636,17637,17638,
91036 17639,17640,17641,17642,17643,17644,17645,17646,17647,17648,17649,17650,
91037 17651,17652,17653,17654,17655,17656,17657,17658,17659,17660,17661,17662,
91038 17663,17664,17665,17666,17667,17668,17669,17670,17671,17672,17673,17674,
91039 17675,17676,17677,17678,17679,17680,17681,17682,17683,17684,17685,17686,
91040 17687,17688,17689,17690,17691,17692,17693,17694,17695,17696,17697,17698,
91041 17699,17700,17701,17702,17703,17704,17705,17706,17707,17708,17709,17710,
91042 17711,17712,17713,17714,17715,17716,17717,17718,17719,17720,17721,17722,
91043 17723,17724,17725,17726,17727,17728,17729,17730,17731,17732,17733,17734,
91044 17735,17736,17737,17738,17739,17740,17741,17742,17743,17744,17745,17746,
91045 17747,17748,17749,17750,17751,17752,17753,17754,17755,17756,17757,17758,
91046 17759,17760,17761,17762,17763,17764,17765,17766,17767,17768,17769,17770,
91047 17771,17772,17773,17774,17775,17776,17777,17778,17779,17780,17781,17782,
91048 17783,17784,17785,17786,17787,17788,17789,17790,17791,17792,17793,17794,
91049 17795,17796,17797,17798,17799,17800,17801,17802,17803,17804,17805,17806,
91050 17807,17808,17809,17810,17811,17812,17813,17814,17815,17816,17817,17818,
91051 17819,17820,17821,17822,17823,17824,17825,17826,17827,17828,17829,17830,
91052 17831,17832,17833,17834,17835,17836,17837,17838,17839,17840,17841,17842,
91053 17843,17844,17845,17846,17847,17848,17849,17850,17851,17852,17853,17854,
91054 17855,17856,17857,17858,17859,17860,17861,17862,17863,17864,17865,17866,
91055 17867,17868,17869,17870,17871,17872,17873,17874,17875,17876,17877,17878,
91056 17879,17880,17881,17882,17883,17884,17885,17886,17887,17888,17889,17890,
91057 17891,17892,17893,17894,17895,17896,17897,17898,17899,17900,17901,17902,
91058 17903,17904,17905,17906,17907,17908,17909,17910,17911,17912,17913,17914,
91059 17915,17916,17917,17918,17919,17920,17921,17922,17923,17924,17925,17926,
91060 17927,17928,17929,17930,17931,17932,17933,17934,17935,17936,17937,17938,
91061 17939,17940,17941,17942,17943,17944,17945,17946,17947,17948,17949,17950,
91062 17951,17952,17953,17954,17955,17956,17957,17958,17959,17960,17961,17962,
91063 17963,17964,17965,17966,17967,17968,17969,17970,17971,17972,17973,17974,
91064 17975,17976,17977,17978,17979,17980,17981,17982,17983,17984,17985,17986,
91065 17987,17988,17989,17990,17991,17992,17993,17994,17995,17996,17997,17998,
91066 17999,18000,18001,18002,18003,18004,18005,18006,18007,18008,18009,18010,
91067 18011,18012,18013,18014,18015,18016,18017,18018,18019,18020,18021,18022,
91068 18023,18024,18025,18026,18027,18028,18029,18030,18031,18032,18033,18034,
91069 18035,18036,18037,18038,18039,18040,18041,18042,18043,18044,18045,18046,
91070 18047,18048,18049,18050,18051,18052,18053,18054,18055,18056,18057,18058,
91071 18059,18060,18061,18062,18063,18064,18065,18066,18067,18068,18069,18070,
91072 18071,18072,18073,18074,18075,18076,18077,18078,18079,18080,18081,18082,
91073 18083,18084,18085,18086,18087,18088,18089,18090,18091,18092,18093,18094,
91074 18095,18096,18097,18098,18099,18100,18101,18102,18103,18104,18105,18106,
91075 18107,18108,18109,18110,18111,18112,18113,18114,18115,18116,18117,18118,
91076 18119,18120,18121,18122,18123,18124,18125,18126,18127,18128,18129,18130,
91077 18131,18132,18133,18134,18135,18136,18137,18138,18139,18140,18141,18142,
91078 18143,18144,18145,18146,18147,18148,18149,18150,18151,18152,18153,18154,
91079 18155,18156,18157,18158,18159,18160,18161,18162,18163,18164,18165,18166,
91080 18167,18168,18169,18170,18171,18172,18173,18174,18175,18176,18177,18178,
91081 18179,18180,18181,18182,18183,18184,18185,18186,18187,18188,18189,18190,
91082 18191,18192,18193,18194,18195,18196,18197,18198,18199,18200,18201,18202,
91083 18203,18204,18205,18206,18207,18208,18209,18210,18211,18212,18213,18214,
91084 18215,18216,18217,18218,18219,18220,18221,18222,18223,18224,18225,18226,
91085 18227,18228,18229,18230,18231,18232,18233,18234,18235,18236,18237,18238,
91086 18239,18240,18241,18242,18243,18244,18245,18246,18247,18248,18249,18250,
91087 18251,18252,18253,18254,18255,18256,18257,18258,18259,18260,18261,18262,
91088 18263,18264,18265,18266,18267,18268,18269,18270,18271,18272,18273,18274,
91089 18275,18276,18277,18278,18279,18280,18281,18282,18283,18284,18285,18286,
91090 18287,18288,18289,18290,18291,18292,18293,18294,18295,18296,18297,18298,
91091 18299,18300,18301,18302,18303,18304,18305,18306,18307,18308,18309,18310,
91092 18311,18312,18313,18314,18315,18316,18317,18318,18319,18320,18321,18322,
91093 18323,18324,18325,18326,18327,18328,18329,18330,18331,18332,18333,18334,
91094 18335,18336,18337,18338,18339,18340,18341,18342,18343,18344,18345,18346,
91095 18347,18348,18349,18350,18351,18352,18353,18354,18355,18356,18357,18358,
91096 18359,18360,18361,18362,18363,18364,18365,18366,18367,18368,18369,18370,
91097 18371,18372,18373,18374,18375,18376,18377,18378,18379,18380,18381,18382,
91098 18383,18384,18385,18386,18387,18388,18389,18390,18391,18392,18393,18394,
91099 18395,18396,18397,18398,18399,18400,18401,18402,18403,18404,18405,18406,
91100 18407,18408,18409,18410,18411,18412,18413,18414,18415,18416,18417,18418,
91101 18419,18420,18421,18422,18423,18424,18425,18426,18427,18428,18429,18430,
91102 18431,18432,18433,18434,18435,18436,18437,18438,18439,18440,18441,18442,
91103 18443,18444,18445,18446,18447,18448,18449,18450,18451,18452,18453,18454,
91104 18455,18456,18457,18458,18459,18460,18461,18462,18463,18464,18465,18466,
91105 18467,18468,18469,18470,18471,18472,18473,18474,18475,18476,18477,18478,
91106 18479,18480,18481,18482,18483,18484,18485,18486,18487,18488,18489,18490,
91107 18491,18492,18493,18494,18495,18496,18497,18498,18499,18500,18501,18502,
91108 18503,18504,18505,18506,18507,18508,18509,18510,18511,18512,18513,18514,
91109 18515,18516,18517,18518,18519,18520,18521,18522,18523,18524,18525,18526,
91110 18527,18528,18529,18530,18531,18532,18533,18534,18535,18536,18537,18538,
91111 18539,18540,18541,18542,18543,18544,18545,18546,18547,18548,18549,18550,
91112 18551,18552,18553,18554,18555,18556,18557,18558,18559,18560,18561,18562,
91113 18563,18564,18565,18566,18567,18568,18569,18570,18571,18572,18573,18574,
91114 18575,18576,18577,18578,18579,18580,18581,18582,18583,18584,18585,18586,
91115 18587,18588,18589,18590,18591,18592,18593,18594,18595,18596,18597,18598,
91116 18599,18600,18601,18602,18603,18604,18605,18606,18607,18608,18609,18610,
91117 18611,18612,18613,18614,18615,18616,18617,18618,18619,18620,18621,18622,
91118 18623,18624,18625,18626,18627,18628,18629,18630,18631,18632,18633,18634,
91119 18635,18636,18637,18638,18639,18640,18641,18642,18643,18644,18645,18646,
91120 18647,18648,18649,18650,18651,18652,18653,18654,18655,18656,18657,18658,
91121 18659,18660,18661,18662,18663,18664,18665,18666,18667,18668,18669,18670,
91122 18671,18672,18673,18674,18675,18676,18677,18678,18679,18680,18681,18682,
91123 18683,18684,18685,18686,18687,18688,18689,18690,18691,18692,18693,18694,
91124 18695,18696,18697,18698,18699,18700,18701,18702,18703,18704,18705,18706,
91125 18707,18708,18709,18710,18711,18712,18713,18714,18715,18716,18717,18718,
91126 18719,18720,18721,18722,18723,18724,18725,18726,18727,18728,18729,18730,
91127 18731,18732,18733,18734,18735,18736,18737,18738,18739,18740,18741,18742,
91128 18743,18744,18745,18746,18747,18748,18749,18750,18751,18752,18753,18754,
91129 18755,18756,18757,18758,18759,18760,18761,18762,18763,18764,18765,18766,
91130 18767,18768,18769,18770,18771,18772,18773,18774,18775,18776,18777,18778,
91131 18779,18780,18781,18782,18783,18784,18785,18786,18787,18788,18789,18790,
91132 18791,18792,18793,18794,18795,18796,18797,18798,18799,18800,18801,18802,
91133 18803,18804,18805,18806,18807,18808,18809,18810,18811,18812,18813,18814,
91134 18815,18816,18817,18818,18819,18820,18821,18822,18823,18824,18825,18826,
91135 18827,18828,18829,18830,18831,18832,18833,18834,18835,18836,18837,18838,
91136 18839,18840,18841,18842,18843,18844,18845,18846,18847,18848,18849,18850,
91137 18851,18852,18853,18854,18855,18856,18857,18858,18859,18860,18861,18862,
91138 18863,18864,18865,18866,18867,18868,18869,18870,18871,18872,18873,18874,
91139 18875,18876,18877,18878,18879,18880,18881,18882,18883,18884,18885,18886,
91140 18887,18888,18889,18890,18891,18892,18893,18894,18895,18896,18897,18898,
91141 18899,18900,18901,18902,18903,18904,18905,18906,18907,18908,18909,18910,
91142 18911,18912,18913,18914,18915,18916,18917,18918,18919,18920,18921,18922,
91143 18923,18924,18925,18926,18927,18928,18929,18930,18931,18932,18933,18934,
91144 18935,18936,18937,18938,18939,18940,18941,18942,18943,18944,18945,18946,
91145 18947,18948,18949,18950,18951,18952,18953,18954,18955,18956,18957,18958,
91146 18959,18960,18961,18962,18963,18964,18965,18966,18967,18968,18969,18970,
91147 18971,18972,18973,18974,18975,18976,18977,18978,18979,18980,18981,18982,
91148 18983,18984,18985,18986,18987,18988,18989,18990,18991,18992,18993,18994,
91149 18995,18996,18997,18998,18999,19000,19001,19002,19003,19004,19005,19006,
91150 19007,19008,19009,19010,19011,19012,19013,19014,19015,19016,19017,19018,
91151 19019,19020,19021,19022,19023,19024,19025,19026,19027,19028,19029,19030,
91152 19031,19032,19033,19034,19035,19036,19037,19038,19039,19040,19041,19042,
91153 19043,19044,19045,19046,19047,19048,19049,19050,19051,19052,19053,19054,
91154 19055,19056,19057,19058,19059,19060,19061,19062,19063,19064,19065,19066,
91155 19067,19068,19069,19070,19071,19072,19073,19074,19075,19076,19077,19078,
91156 19079,19080,19081,19082,19083,19084,19085,19086,19087,19088,19089,19090,
91157 19091,19092,19093,19094,19095,19096,19097,19098,19099,19100,19101,19102,
91158 19103,19104,19105,19106,19107,19108,19109,19110,19111,19112,19113,19114,
91159 19115,19116,19117,19118,19119,19120,19121,19122,19123,19124,19125,19126,
91160 19127,19128,19129,19130,19131,19132,19133,19134,19135,19136,19137,19138,
91161 19139,19140,19141,19142,19143,19144,19145,19146,19147,19148,19149,19150,
91162 19151,19152,19153,19154,19155,19156,19157,19158,19159,19160,19161,19162,
91163 19163,19164,19165,19166,19167,19168,19169,19170,19171,19172,19173,19174,
91164 19175,19176,19177,19178,19179,19180,19181,19182,19183,19184,19185,19186,
91165 19187,19188,19189,19190,19191,19192,19193,19194,19195,19196,19197,19198,
91166 19199,19200,19201,19202,19203,19204,19205,19206,19207,19208,19209,19210,
91167 19211,19212,19213,19214,19215,19216,19217,19218,19219,19220,19221,19222,
91168 19223,19224,19225,19226,19227,19228,19229,19230,19231,19232,19233,19234,
91169 19235,19236,19237,19238,19239,19240,19241,19242,19243,19244,19245,19246,
91170 19247,19248,19249,19250,19251,19252,19253,19254,19255,19256,19257,19258,
91171 19259,19260,19261,19262,19263,19264,19265,19266,19267,19268,19269,19270,
91172 19271,19272,19273,19274,19275,19276,19277,19278,19279,19280,19281,19282,
91173 19283,19284,19285,19286,19287,19288,19289,19290,19291,19292,19293,19294,
91174 19295,19296,19297,19298,19299,19300,19301,19302,19303,19304,19305,19306,
91175 19307,19308,19309,19310,19311,19312,19313,19314,19315,19316,19317,19318,
91176 19319,19320,19321,19322,19323,19324,19325,19326,19327,19328,19329,19330,
91177 19331,19332,19333,19334,19335,19336,19337,19338,19339,19340,19341,19342,
91178 19343,19344,19345,19346,19347,19348,19349,19350,19351,19352,19353,19354,
91179 19355,19356,19357,19358,19359,19360,19361,19362,19363,19364,19365,19366,
91180 19367,19368,19369,19370,19371,19372,19373,19374,19375,19376,19377,19378,
91181 19379,19380,19381,19382,19383,19384,19385,19386,19387,19388,19389,19390,
91182 19391,19392,19393,19394,19395,19396,19397,19398,19399,19400,19401,19402,
91183 19403,19404,19405,19406,19407,19408,19409,19410,19411,19412,19413,19414,
91184 19415,19416,19417,19418,19419,19420,19421,19422,19423,19424,19425,19426,
91185 19427,19428,19429,19430,19431,19432,19433,19434,19435,19436,19437,19438,
91186 19439,19440,19441,19442,19443,19444,19445,19446,19447,19448,19449,19450,
91187 19451,19452,19453,19454,19455,19456,19457,19458,19459,19460,19461,19462,
91188 19463,19464,19465,19466,19467,19468,19469,19470,19471,19472,19473,19474,
91189 19475,19476,19477,19478,19479,19480,19481,19482,19483,19484,19485,19486,
91190 19487,19488,19489,19490,19491,19492,19493,19494,19495,19496,19497,19498,
91191 19499,19500,19501,19502,19503,19504,19505,19506,19507,19508,19509,19510,
91192 19511,19512,19513,19514,19515,19516,19517,19518,19519,19520,19521,19522,
91193 19523,19524,19525,19526,19527,19528,19529,19530,19531,19532,19533,19534,
91194 19535,19536,19537,19538,19539,19540,19541,19542,19543,19544,19545,19546,
91195 19547,19548,19549,19550,19551,19552,19553,19554,19555,19556,19557,19558,
91196 19559,19560,19561,19562,19563,19564,19565,19566,19567,19568,19569,19570,
91197 19571,19572,19573,19574,19575,19576,19577,19578,19579,19580,19581,19582,
91198 19583,19584,19585,19586,19587,19588,19589,19590,19591,19592,19593,19594,
91199 19595,19596,19597,19598,19599,19600,19601,19602,19603,19604,19605,19606,
91200 19607,19608,19609,19610,19611,19612,19613,19614,19615,19616,19617,19618,
91201 19619,19620,19621,19622,19623,19624,19625,19626,19627,19628,19629,19630,
91202 19631,19632,19633,19634,19635,19636,19637,19638,19639,19640,19641,19642,
91203 19643,19644,19645,19646,19647,19648,19649,19650,19651,19652,19653,19654,
91204 19655,19656,19657,19658,19659,19660,19661,19662,19663,19664,19665,19666,
91205 19667,19668,19669,19670,19671,19672,19673,19674,19675,19676,19677,19678,
91206 19679,19680,19681,19682,19683,19684,19685,19686,19687,19688,19689,19690,
91207 19691,19692,19693,19694,19695,19696,19697,19698,19699,19700,19701,19702,
91208 19703,19704,19705,19706,19707,19708,19709,19710,19711,19712,19713,19714,
91209 19715,19716,19717,19718,19719,19720,19721,19722,19723,19724,19725,19726,
91210 19727,19728,19729,19730,19731,19732,19733,19734,19735,19736,19737,19738,
91211 19739,19740,19741,19742,19743,19744,19745,19746,19747,19748,19749,19750,
91212 19751,19752,19753,19754,19755,19756,19757,19758,19759,19760,19761,19762,
91213 19763,19764,19765,19766,19767,19768,19769,19770,19771,19772,19773,19774,
91214 19775,19776,19777,19778,19779,19780,19781,19782,19783,19784,19785,19786,
91215 19787,19788,19789,19790,19791,19792,19793,19794,19795,19796,19797,19798,
91216 19799,19800,19801,19802,19803,19804,19805,19806,19807,19808,19809,19810,
91217 19811,19812,19813,19814,19815,19816,19817,19818,19819,19820,19821,19822,
91218 19823,19824,19825,19826,19827,19828,19829,19830,19831,19832,19833,19834,
91219 19835,19836,19837,19838,19839,19840,19841,19842,19843,19844,19845,19846,
91220 19847,19848,19849,19850,19851,19852,19853,19854,19855,19856,19857,19858,
91221 19859,19860,19861,19862,19863,19864,19865,19866,19867,19868,19869,19870,
91222 19871,19872,19873,19874,19875,19876,19877,19878,19879,19880,19881,19882,
91223 19883,19884,19885,19886,19887,19888,19889,19890,19891,19892,19893,19894,
91224 19895,19896,19897,19898,19899,19900,19901,19902,19903,19904,19905,19906,
91225 19907,19908,19909,19910,19911,19912,19913,19914,19915,19916,19917,19918,
91226 19919,19920,19921,19922,19923,19924,19925,19926,19927,19928,19929,19930,
91227 19931,19932,19933,19934,19935,19936,19937,19938,19939,19940,19941,19942,
91228 19943,19944,19945,19946,19947,19948,19949,19950,19951,19952,19953,19954,
91229 19955,19956,19957,19958,19959,19960,19961,19962,19963,19964,19965,19966,
91230 19967,19968,19969,19970,19971,19972,19973,19974,19975,19976,19977,19978,
91231 19979,19980,19981,19982,19983,19984,19985,19986,19987,19988,19989,19990,
91232 19991,19992,19993,19994,19995,19996,19997,19998,19999,20000,20001,20002,
91233 20003,20004,20005,20006,20007,20008,20009,20010,20011,20012,20013,20014,
91234 20015,20016,20017,20018,20019,20020,20021,20022,20023,20024,20025,20026,
91235 20027,20028,20029,20030,20031,20032,20033,20034,20035,20036,20037,20038,
91236 20039,20040,20041,20042,20043,20044,20045,20046,20047,20048,20049,20050,
91237 20051,20052,20053,20054,20055,20056,20057,20058,20059,20060,20061,20062,
91238 20063,20064,20065,20066,20067,20068,20069,20070,20071,20072,20073,20074,
91239 20075,20076,20077,20078,20079,20080,20081,20082,20083,20084,20085,20086,
91240 20087,20088,20089,20090,20091,20092,20093,20094,20095,20096,20097,20098,
91241 20099,20100,20101,20102,20103,20104,20105,20106,20107,20108,20109,20110,
91242 20111,20112,20113,20114,20115,20116,20117,20118,20119,20120,20121,20122,
91243 20123,20124,20125,20126,20127,20128,20129,20130,20131,20132,20133,20134,
91244 20135,20136,20137,20138,20139,20140,20141,20142,20143,20144,20145,20146,
91245 20147,20148,20149,20150,20151,20152,20153,20154,20155,20156,20157,20158,
91246 20159,20160,20161,20162,20163,20164,20165,20166,20167,20168,20169,20170,
91247 20171,20172,20173,20174,20175,20176,20177,20178,20179,20180,20181,20182,
91248 20183,20184,20185,20186,20187,20188,20189,20190,20191,20192,20193,20194,
91249 20195,20196,20197,20198,20199,20200,20201,20202,20203,20204,20205,20206,
91250 20207,20208,20209,20210,20211,20212,20213,20214,20215,20216,20217,20218,
91251 20219,20220,20221,20222,20223,20224,20225,20226,20227,20228,20229,20230,
91252 20231,20232,20233,20234,20235,20236,20237,20238,20239,20240,20241,20242,
91253 20243,20244,20245,20246,20247,20248,20249,20250,20251,20252,20253,20254,
91254 20255,20256,20257,20258,20259,20260,20261,20262,20263,20264,20265,20266,
91255 20267,20268,20269,20270,20271,20272,20273,20274,20275,20276,20277,20278,
91256 20279,20280,20281,20282,20283,20284,20285,20286,20287,20288,20289,20290,
91257 20291,20292,20293,20294,20295,20296,20297,20298,20299,20300,20301,20302,
91258 20303,20304,20305,20306,20307,20308,20309,20310,20311,20312,20313,20314,
91259 20315,20316,20317,20318,20319,20320,20321,20322,20323,20324,20325,20326,
91260 20327,20328,20329,20330,20331,20332,20333,20334,20335,20336,20337,20338,
91261 20339,20340,20341,20342,20343,20344,20345,20346,20347,20348,20349,20350,
91262 20351,20352,20353,20354,20355,20356,20357,20358,20359,20360,20361,20362,
91263 20363,20364,20365,20366,20367,20368,20369,20370,20371,20372,20373,20374,
91264 20375,20376,20377,20378,20379,20380,20381,20382,20383,20384,20385,20386,
91265 20387,20388,20389,20390,20391,20392,20393,20394,20395,20396,20397,20398,
91266 20399,20400,20401,20402,20403,20404,20405,20406,20407,20408,20409,20410,
91267 20411,20412,20413,20414,20415,20416,20417,20418,20419,20420,20421,20422,
91268 20423,20424,20425,20426,20427,20428,20429,20430,20431,20432,20433,20434,
91269 20435,20436,20437,20438,20439,20440,20441,20442,20443,20444,20445,20446,
91270 20447,20448,20449,20450,20451,20452,20453,20454,20455,20456,20457,20458,
91271 20459,20460,20461,20462,20463,20464,20465,20466,20467,20468,20469,20470,
91272 20471,20472,20473,20474,20475,20476,20477,20478,20479,20480,20481,20482,
91273 20483,20484,20485,20486,20487,20488,20489,20490,20491,20492,20493,20494,
91274 20495,20496,20497,20498,20499,20500,20501,20502,20503,20504,20505,20506,
91275 20507,20508,20509,20510,20511,20512,20513,20514,20515,20516,20517,20518,
91276 20519,20520,20521,20522,20523,20524,20525,20526,20527,20528,20529,20530,
91277 20531,20532,20533,20534,20535,20536,20537,20538,20539,20540,20541,20542,
91278 20543,20544,20545,20546,20547,20548,20549,20550,20551,20552,20553,20554,
91279 20555,20556,20557,20558,20559,20560,20561,20562,20563,20564,20565,20566,
91280 20567,20568,20569,20570,20571,20572,20573,20574,20575,20576,20577,20578,
91281 20579,20580,20581,20582,20583,20584,20585,20586,20587,20588,20589,20590,
91282 20591,20592,20593,20594,20595,20596,20597,20598,20599,20600,20601,20602,
91283 20603,20604,20605,20606,20607,20608,20609,20610,20611,20612,20613,20614,
91284 20615,20616,20617,20618,20619,20620,20621,20622,20623,20624,20625,20626,
91285 20627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,
91286 20639,20640,20641,20642,20643,20644,20645,20646,20647,20648,20649,20650,
91287 20651,20652,20653,20654,20655,20656,20657,20658,20659,20660,20661,20662,
91288 20663,20664,20665,20666,20667,20668,20669,20670,20671,20672,20673,20674,
91289 20675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,
91290 20687,20688,20689,20690,20691,20692,20693,20694,20695,20696,20697,20698,
91291 20699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20710,
91292 20711,20712,20713,20714,20715,20716,20717,20718,20719,20720,20721,20722,
91293 20723,20724,20725,20726,20727,20728,20729,20730,20731,20732,20733,20734,
91294 20735,20736,20737,20738,20739,20740,20741,20742,20743,20744,20745,20746,
91295 20747,20748,20749,20750,20751,20752,20753,20754,20755,20756,20757,20758,
91296 20759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20769,20770,
91297 20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,
91298 20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,
91299 20795,20796,20797,20798,20799,20800,20801,20802,20803,20804,20805,20806,
91300 20807,20808,20809,20810,20811,20812,20813,20814,20815,20816,20817,20818,
91301 20819,20820,20821,20822,20823,20824,20825,20826,20827,20828,20829,20830,
91302 20831,20832,20833,20834,20835,20836,20837,20838,20839,20840,20841,20842,
91303 20843,20844,20845,20846,20847,20848,20849,20850,20851,20852,20853,20854,
91304 20855,20856,20857,20858,20859,20860,20861,20862,20863,20864,20865,20866,
91305 20867,20868,20869,20870,20871,20872,20873,20874,20875,20876,20877,20878,
91306 20879,20880,20881,20882,20883,20884,20885,20886,20887,20888,20889,20890,
91307 20891,20892,20893,20894,20895,20896,20897,20898,20899,20900,20901,20902,
91308 20903,20904,20905,20906,20907,20908,20909,20910,20911,20912,20913,20914,
91309 20915,20916,20917,20918,20919,20920,20921,20922,20923,20924,20925,20926,
91310 20927,20928,20929,20930,20931,20932,20933,20934,20935,20936,20937,20938,
91311 20939,20940,20941,20942,20943,20944,20945,20946,20947,20948,20949,20950,
91312 20951,20952,20953,20954,20955,20956,20957,20958,20959,20960,20961,20962,
91313 20963,20964,20965,20966,20967,20968,20969,20970,20971,20972,20973,20974,
91314 20975,20976,20977,20978,20979,20980,20981,20982,20983,20984,20985,20986,
91315 20987,20988,20989,20990,20991,20992,20993,20994,20995,20996,20997,20998,
91316 20999,21000,21001,21002,21003,21004,21005,21006,21007,21008,21009,21010,
91317 21011,21012,21013,21014,21015,21016,21017,21018,21019,21020,21021,21022,
91318 21023,21024,21025,21026,21027,21028,21029,21030,21031,21032,21033,21034,
91319 21035,21036,21037,21038,21039,21040,21041,21042,21043,21044,21045,21046,
91320 21047,21048,21049,21050,21051,21052,21053,21054,21055,21056,21057,21058,
91321 21059,21060,21061,21062,21063,21064,21065,21066,21067,21068,21069,21070,
91322 21071,21072,21073,21074,21075,21076,21077,21078,21079,21080,21081,21082,
91323 21083,21084,21085,21086,21087,21088,21089,21090,21091,21092,21093,21094,
91324 21095,21096,21097,21098,21099,21100,21101,21102,21103,21104,21105,21106,
91325 21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21117,21118,
91326 21119,21120,21121,21122,21123,21124,21125,21126,21127,21128,21129,21130,
91327 21131,21132,21133,21134,21135,21136,21137,21138,21139,21140,21141,21142,
91328 21143,21144,21145,21146,21147,21148,21149,21150,21151,21152,21153,21154,
91329 21155,21156,21157,21158,21159,21160,21161,21162,21163,21164,21165,21166,
91330 21167,21168,21169,21170,21171,21172,21173,21174,21175,21176,21177,21178,
91331 21179,21180,21181,21182,21183,21184,21185,21186,21187,21188,21189,21190,
91332 21191,21192,21193,21194,21195,21196,21197,21198,21199,21200,21201,21202,
91333 21203,21204,21205,21206,21207,21208,21209,21210,21211,21212,21213,21214,
91334 21215,21216,21217,21218,21219,21220,21221,21222,21223,21224,21225,21226,
91335 21227,21228,21229,21230,21231,21232,21233,21234,21235,21236,21237,21238,
91336 21239,21240,21241,21242,21243,21244,21245,21246,21247,21248,21249,21250,
91337 21251,21252,21253,21254,21255,21256,21257,21258,21259,21260,21261,21262,
91338 21263,21264,21265,21266,21267,21268,21269,21270,21271,21272,21273,21274,
91339 21275,21276,21277,21278,21279,21280,21281,21282,21283,21284,21285,21286,
91340 21287,21288,21289,21290,21291,21292,21293,21294,21295,21296,21297,21298,
91341 21299,21300,21301,21302,21303,21304,21305,21306,21307,21308,21309,21310,
91342 21311,21312,21313,21314,21315,21316,21317,21318,21319,21320,21321,21322,
91343 21323,21324,21325,21326,21327,21328,21329,21330,21331,21332,21333,21334,
91344 21335,21336,21337,21338,21339,21340,21341,21342,21343,21344,21345,21346,
91345 21347,21348,21349,21350,21351,21352,21353,21354,21355,21356,21357,21358,
91346 21359,21360,21361,21362,21363,21364,21365,21366,21367,21368,21369,21370,
91347 21371,21372,21373,21374,21375,21376,21377,21378,21379,21380,21381,21382,
91348 21383,21384,21385,21386,21387,21388,21389,21390,21391,21392,21393,21394,
91349 21395,21396,21397,21398,21399,21400,21401,21402,21403,21404,21405,21406,
91350 21407,21408,21409,21410,21411,21412,21413,21414,21415,21416,21417,21418,
91351 21419,21420,21421,21422,21423,21424,21425,21426,21427,21428,21429,21430,
91352 21431,21432,21433,21434,21435,21436,21437,21438,21439,21440,21441,21442,
91353 21443,21444,21445,21446,21447,21448,21449,21450,21451,21452,21453,21454,
91354 21455,21456,21457,21458,21459,21460,21461,21462,21463,21464,21465,21466,
91355 21467,21468,21469,21470,21471,21472,21473,21474,21475,21476,21477,21478,
91356 21479,21480,21481,21482,21483,21484,21485,21486,21487,21488,21489,21490,
91357 21491,21492,21493,21494,21495,21496,21497,21498,21499,21500,21501,21502,
91358 21503,21504,21505,21506,21507,21508,21509,21510,21511,21512,21513,21514,
91359 21515,21516,21517,21518,21519,21520,21521,21522,21523,21524,21525,21526,
91360 21527,21528,21529,21530,21531,21532,21533,21534,21535,21536,21537,21538,
91361 21539,21540,21541,21542,21543,21544,21545,21546,21547,21548,21549,21550,
91362 21551,21552,21553,21554,21555,21556,21557,21558,21559,21560,21561,21562,
91363 21563,21564,21565,21566,21567,21568,21569,21570,21571,21572,21573,21574,
91364 21575,21576,21577,21578,21579,21580,21581,21582,21583,21584,21585,21586,
91365 21587,21588,21589,21590,21591,21592,21593,21594,21595,21596,21597,21598,
91366 21599,21600,21601,21602,21603,21604,21605,21606,21607,21608,21609,21610,
91367 21611,21612,21613,21614,21615,21616,21617,21618,21619,21620,21621,21622,
91368 21623,21624,21625,21626,21627,21628,21629,21630,21631,21632,21633,21634,
91369 21635,21636,21637,21638,21639,21640,21641,21642,21643,21644,21645,21646,
91370 21647,21648,21649,21650,21651,21652,21653,21654,21655,21656,21657,21658,
91371 21659,21660,21661,21662,21663,21664,21665,21666,21667,21668,21669,21670,
91372 21671,21672,21673,21674,21675,21676,21677,21678,21679,21680,21681,21682,
91373 21683,21684,21685,21686,21687,21688,21689,21690,21691,21692,21693,21694,
91374 21695,21696,21697,21698,21699,21700,21701,21702,21703,21704,21705,21706,
91375 21707,21708,21709,21710,21711,21712,21713,21714,21715,21716,21717,21718,
91376 21719,21720,21721,21722,21723,21724,21725,21726,21727,21728,21729,21730,
91377 21731,21732,21733,21734,21735,21736,21737,21738,21739,21740,21741,21742,
91378 21743,21744,21745,21746,21747,21748,21749,21750,21751,21752,21753,21754,
91379 21755,21756,21757,21758,21759,21760,21761,21762,21763,21764,21765,21766,
91380 21767,21768,21769,21770,21771,21772,21773,21774,21775,21776,21777,21778,
91381 21779,21780,21781,21782,21783,21784,21785,21786,21787,21788,21789,21790,
91382 21791,21792,21793,21794,21795,21796,21797,21798,21799,21800,21801,21802,
91383 21803,21804,21805,21806,21807,21808,21809,21810,21811,21812,21813,21814,
91384 21815,21816,21817,21818,21819,21820,21821,21822,21823,21824,21825,21826,
91385 21827,21828,21829,21830,21831,21832,21833,21834,21835,21836,21837,21838,
91386 21839,21840,21841,21842,21843,21844,21845,21846,21847,21848,21849,21850,
91387 21851,21852,21853,21854,21855,21856,21857,21858,21859,21860,21861,21862,
91388 21863,21864,21865,21866,21867,21868,21869,21870,21871,21872,21873,21874,
91389 21875,21876,21877,21878,21879,21880,21881,21882,21883,21884,21885,21886,
91390 21887,21888,21889,21890,21891,21892,21893,21894,21895,21896,21897,21898,
91391 21899,21900,21901,21902,21903,21904,21905,21906,21907,21908,21909,21910,
91392 21911,21912,21913,21914,21915,21916,21917,21918,21919,21920,21921,21922,
91393 21923,21924,21925,21926,21927,21928,21929,21930,21931,21932,21933,21934,
91394 21935,21936,21937,21938,21939,21940,21941,21942,21943,21944,21945,21946,
91395 21947,21948,21949,21950,21951,21952,21953,21954,21955,21956,21957,21958,
91396 21959,21960,21961,21962,21963,21964,21965,21966,21967,21968,21969,21970,
91397 21971,21972,21973,21974,21975,21976,21977,21978,21979,21980,21981,21982,
91398 21983,21984,21985,21986,21987,21988,21989,21990,21991,21992,21993,21994,
91399 21995,21996,21997,21998,21999,22000,22001,22002,22003,22004,22005,22006,
91400 22007,22008,22009,22010,22011,22012,22013,22014,22015,22016,22017,22018,
91401 22019,22020,22021,22022,22023,22024,22025,22026,22027,22028,22029,22030,
91402 22031,22032,22033,22034,22035,22036,22037,22038,22039,22040,22041,22042,
91403 22043,22044,22045,22046,22047,22048,22049,22050,22051,22052,22053,22054,
91404 22055,22056,22057,22058,22059,22060,22061,22062,22063,22064,22065,22066,
91405 22067,22068,22069,22070,22071,22072,22073,22074,22075,22076,22077,22078,
91406 22079,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,
91407 22091,22092,22093,22094,22095,22096,22097,22098,22099,22100,22101,22102,
91408 22103,22104,22105,22106,22107,22108,22109,22110,22111,22112,22113,22114,
91409 22115,22116,22117,22118,22119,22120,22121,22122,22123,22124,22125,22126,
91410 22127,22128,22129,22130,22131,22132,22133,22134,22135,22136,22137,22138,
91411 22139,22140,22141,22142,22143,22144,22145,22146,22147,22148,22149,22150,
91412 22151,22152,22153,22154,22155,22156,22157,22158,22159,22160,22161,22162,
91413 22163,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,
91414 22175,22176,22177,22178,22179,22180,22181,22182,22183,22184,22185,22186,
91415 22187,22188,22189,22190,22191,22192,22193,22194,22195,22196,22197,22198,
91416 22199,22200,22201,22202,22203,22204,22205,22206,22207,22208,22209,22210,
91417 22211,22212,22213,22214,22215,22216,22217,22218,22219,22220,22221,22222,
91418 22223,22224,22225,22226,22227,22228,22229,22230,22231,22232,22233,22234,
91419 22235,22236,22237,22238,22239,22240,22241,22242,22243,22244,22245,22246,
91420 22247,22248,22249,22250,22251,22252,22253,22254,22255,22256,22257,22258,
91421 22259,22260,22261,22262,22263,22264,22265,22266,22267,22268,22269,22270,
91422 22271,22272,22273,22274,22275,22276,22277,22278,22279,22280,22281,22282,
91423 22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,
91424 22295,22296,22297,22298,22299,22300,22301,22302,22303,22304,22305,22306,
91425 22307,22308,22309,22310,22311,22312,22313,22314,22315,22316,22317,22318,
91426 22319,22320,22321,22322,22323,22324,22325,22326,22327,22328,22329,22330,
91427 22331,22332,22333,22334,22335,22336,22337,22338,22339,22340,22341,22342,
91428 22343,22344,22345,22346,22347,22348,22349,22350,22351,22352,22353,22354,
91429 22355,22356,22357,22358,22359,22360,22361,22362,22363,22364,22365,22366,
91430 22367,22368,22369,22370,22371,22372,22373,22374,22375,22376,22377,22378,
91431 22379,22380,22381,22382,22383,22384,22385,22386,22387,22388,22389,22390,
91432 22391,22392,22393,22394,22395,22396,22397,22398,22399,22400,22401,22402,
91433 22403,22404,22405,22406,22407,22408,22409,22410,22411,22412,22413,22414,
91434 22415,22416,22417,22418,22419,22420,22421,22422,22423,22424,22425,22426,
91435 22427,22428,22429,22430,22431,22432,22433,22434,22435,22436,22437,22438,
91436 22439,22440,22441,22442,22443,22444,22445,22446,22447,22448,22449,22450,
91437 22451,22452,22453,22454,22455,22456,22457,22458,22459,22460,22461,22462,
91438 22463,22464,22465,22466,22467,22468,22469,22470,22471,22472,22473,22474,
91439 22475,22476,22477,22478,22479,22480,22481,22482,22483,22484,22485,22486,
91440 22487,22488,22489,22490,22491,22492,22493,22494,22495,22496,22497,22498,
91441 22499,22500,22501,22502,22503,22504,22505,22506,22507,22508,22509,22510,
91442 22511,22512,22513,22514,22515,22516,22517,22518,22519,22520,22521,22522,
91443 22523,22524,22525,22526,22527,22528,22529,22530,22531,22532,22533,22534,
91444 22535,22536,22537,22538,22539,22540,22541,22542,22543,22544,22545,22546,
91445 22547,22548,22549,22550,22551,22552,22553,22554,22555,22556,22557,22558,
91446 22559,22560,22561,22562,22563,22564,22565,22566,22567,22568,22569,22570,
91447 22571,22572,22573,22574,22575,22576,22577,22578,22579,22580,22581,22582,
91448 22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,
91449 22595,22596,22597,22598,22599,22600,22601,22602,22603,22604,22605,22606,
91450 22607,22608,22609,22610,22611,22612,22613,22614,22615,22616,22617,22618,
91451 22619,22620,22621,22622,22623,22624,22625,22626,22627,22628,22629,22630,
91452 22631,22632,22633,22634,22635,22636,22637,22638,22639,22640,22641,22642,
91453 22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22654,
91454 22655,22656,22657,22658,22659,22660,22661,22662,22663,22664,22665,22666,
91455 22667,22668,22669,22670,22671,22672,22673,22674,22675,22676,22677,22678,
91456 22679,22680,22681,22682,22683,22684,22685,22686,22687,22688,22689,22690,
91457 22691,22692,22693,22694,22695,22696,22697,22698,22699,22700,22701,22702,
91458 22703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,
91459 22715,22716,22717,22718,22719,22720,22721,22722,22723,22724,22725,22726,
91460 22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22737,22738,
91461 22739,22740,22741,22742,22743,22744,22745,22746,22747,22748,22749,22750,
91462 22751,22752,22753,22754,22755,22756,22757,22758,22759,22760,22761,22762,
91463 22763,22764,22765,22766,22767,22768,22769,22770,22771,22772,22773,22774,
91464 22775,22776,22777,22778,22779,22780,22781,22782,22783,22784,22785,22786,
91465 22787,22788,22789,22790,22791,22792,22793,22794,22795,22796,22797,22798,
91466 22799,22800,22801,22802,22803,22804,22805,22806,22807,22808,22809,22810,
91467 22811,22812,22813,22814,22815,22816,22817,22818,22819,22820,22821,22822,
91468 22823,22824,22825,22826,22827,22828,22829,22830,22831,22832,22833,22834,
91469 22835,22836,22837,22838,22839,22840,22841,22842,22843,22844,22845,22846,
91470 22847,22848,22849,22850,22851,22852,22853,22854,22855,22856,22857,22858,
91471 22859,22860,22861,22862,22863,22864,22865,22866,22867,22868,22869,22870,
91472 22871,22872,22873,22874,22875,22876,22877,22878,22879,22880,22881,22882,
91473 22883,22884,22885,22886,22887,22888,22889,22890,22891,22892,22893,22894,
91474 22895,22896,22897,22898,22899,22900,22901,22902,22903,22904,22905,22906,
91475 22907,22908,22909,22910,22911,22912,22913,22914,22915,22916,22917,22918,
91476 22919,22920,22921,22922,22923,22924,22925,22926,22927,22928,22929,22930,
91477 22931,22932,22933,22934,22935,22936,22937,22938,22939,22940,22941,22942,
91478 22943,22944,22945,22946,22947,22948,22949,22950,22951,22952,22953,22954,
91479 22955,22956,22957,22958,22959,22960,22961,22962,22963,22964,22965,22966,
91480 22967,22968,22969,22970,22971,22972,22973,22974,22975,22976,22977,22978,
91481 22979,22980,22981,22982,22983,22984,22985,22986,22987,22988,22989,22990,
91482 22991,22992,22993,22994,22995,22996,22997,22998,22999,23000,23001,23002,
91483 23003,23004,23005,23006,23007,23008,23009,23010,23011,23012,23013,23014,
91484 23015,23016,23017,23018,23019,23020,23021,23022,23023,23024,23025,23026,
91485 23027,23028,23029,23030,23031,23032,23033,23034,23035,23036,23037,23038,
91486 23039,23040,23041,23042,23043,23044,23045,23046,23047,23048,23049,23050,
91487 23051,23052,23053,23054,23055,23056,23057,23058,23059,23060,23061,23062,
91488 23063,23064,23065,23066,23067,23068,23069,23070,23071,23072,23073,23074,
91489 23075,23076,23077,23078,23079,23080,23081,23082,23083,23084,23085,23086,
91490 23087,23088,23089,23090,23091,23092,23093,23094,23095,23096,23097,23098,
91491 23099,23100,23101,23102,23103,23104,23105,23106,23107,23108,23109,23110,
91492 23111,23112,23113,23114,23115,23116,23117,23118,23119,23120,23121,23122,
91493 23123,23124,23125,23126,23127,23128,23129,23130,23131,23132,23133,23134,
91494 23135,23136,23137,23138,23139,23140,23141,23142,23143,23144,23145,23146,
91495 23147,23148,23149,23150,23151,23152,23153,23154,23155,23156,23157,23158,
91496 23159,23160,23161,23162,23163,23164,23165,23166,23167,23168,23169,23170,
91497 23171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,
91498 23183,23184,23185,23186,23187,23188,23189,23190,23191,23192,23193,23194,
91499 23195,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206,
91500 23207,23208,23209,23210,23211,23212,23213,23214,23215,23216,23217,23218,
91501 23219,23220,23221,23222,23223,23224,23225,23226,23227,23228,23229,23230,
91502 23231,23232,23233,23234,23235,23236,23237,23238,23239,23240,23241,23242,
91503 23243,23244,23245,23246,23247,23248,23249,23250,23251,23252,23253,23254,
91504 23255,23256,23257,23258,23259,23260,23261,23262,23263,23264,23265,23266,
91505 23267,23268,23269,23270,23271,23272,23273,23274,23275,23276,23277,23278,
91506 23279,23280,23281,23282,23283,23284,23285,23286,23287,23288,23289,23290,
91507 23291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302,
91508 23303,23304,23305,23306,23307,23308,23309,23310,23311,23312,23313,23314,
91509 23315,23316,23317,23318,23319,23320,23321,23322,23323,23324,23325,23326,
91510 23327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338,
91511 23339,23340,23341,23342,23343,23344,23345,23346,23347,23348,23349,23350,
91512 23351,23352,23353,23354,23355,23356,23357,23358,23359,23360,23361,23362,
91513 23363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,
91514 23375,23376,23377,23378,23379,23380,23381,23382,23383,23384,23385,23386,
91515 23387,23388,23389,23390,23391,23392,23393,23394,23395,23396,23397,23398,
91516 23399,23400,23401,23402,23403,23404,23405,23406,23407,23408,23409,23410,
91517 23411,23412,23413,23414,23415,23416,23417,23418,23419,23420,23421,23422,
91518 23423,23424,23425,23426,23427,23428,23429,23430,23431,23432,23433,23434,
91519 23435,23436,23437,23438,23439,23440,23441,23442,23443,23444,23445,23446,
91520 23447,23448,23449,23450,23451,23452,23453,23454,23455,23456,23457,23458,
91521 23459,23460,23461,23462,23463,23464,23465,23466,23467,23468,23469,23470,
91522 23471,23472,23473,23474,23475,23476,23477,23478,23479,23480,23481,23482,
91523 23483,23484,23485,23486,23487,23488,23489,23490,23491,23492,23493,23494,
91524 23495,23496,23497,23498,23499,23500,23501,23502,23503,23504,23505,23506,
91525 23507,23508,23509,23510,23511,23512,23513,23514,23515,23516,23517,23518,
91526 23519,23520,23521,23522,23523,23524,23525,23526,23527,23528,23529,23530,
91527 23531,23532,23533,23534,23535,23536,23537,23538,23539,23540,23541,23542,
91528 23543,23544,23545,23546,23547,23548,23549,23550,23551,23552,23553,23554,
91529 23555,23556,23557,23558,23559,23560,23561,23562,23563,23564,23565,23566,
91530 23567,23568,23569,23570,23571,23572,23573,23574,23575,23576,23577,23578,
91531 23579,23580,23581,23582,23583,23584,23585,23586,23587,23588,23589,23590,
91532 23591,23592,23593,23594,23595,23596,23597,23598,23599,23600,23601,23602,
91533 23603,23604,23605,23606,23607,23608,23609,23610,23611,23612,23613,23614,
91534 23615,23616,23617,23618,23619,23620,23621,23622,23623,23624,23625,23626,
91535 23627,23628,23629,23630,23631,23632,23633,23634,23635,23636,23637,23638,
91536 23639,23640,23641,23642,23643,23644,23645,23646,23647,23648,23649,23650,
91537 23651,23652,23653,23654,23655,23656,23657,23658,23659,23660,23661,23662,
91538 23663,23664,23665,23666,23667,23668,23669,23670,23671,23672,23673,23674,
91539 23675,23676,23677,23678,23679,23680,23681,23682,23683,23684,23685,23686,
91540 23687,23688,23689,23690,23691,23692,23693,23694,23695,23696,23697,23698,
91541 23699,23700,23701,23702,23703,23704,23705,23706,23707,23708,23709,23710,
91542 23711,23712,23713,23714,23715,23716,23717,23718,23719,23720,23721,23722,
91543 23723,23724,23725,23726,23727,23728,23729,23730,23731,23732,23733,23734,
91544 23735,23736,23737,23738,23739,23740,23741,23742,23743,23744,23745,23746,
91545 23747,23748,23749,23750,23751,23752,23753,23754,23755,23756,23757,23758,
91546 23759,23760,23761,23762,23763,23764,23765,23766,23767,23768,23769,23770,
91547 23771,23772,23773,23774,23775,23776,23777,23778,23779,23780,23781,23782,
91548 23783,23784,23785,23786,23787,23788,23789,23790,23791,23792,23793,23794,
91549 23795,23796,23797,23798,23799,23800,23801,23802,23803,23804,23805,23806,
91550 23807,23808,23809,23810,23811,23812,23813,23814,23815,23816,23817,23818,
91551 23819,23820,23821,23822,23823,23824,23825,23826,23827,23828,23829,23830,
91552 23831,23832,23833,23834,23835,23836,23837,23838,23839,23840,23841,23842,
91553 23843,23844,23845,23846,23847,23848,23849,23850,23851,23852,23853,23854,
91554 23855,23856,23857,23858,23859,23860,23861,23862,23863,23864,23865,23866,
91555 23867,23868,23869,23870,23871,23872,23873,23874,23875,23876,23877,23878,
91556 23879,23880,23881,23882,23883,23884,23885,23886,23887,23888,23889,23890,
91557 23891,23892,23893,23894,23895,23896,23897,23898,23899,23900,23901,23902,
91558 23903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23913,23914,
91559 23915,23916,23917,23918,23919,23920,23921,23922,23923,23924,23925,23926,
91560 23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23938,
91561 23939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,
91562 23951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23961,23962,
91563 23963,23964,23965,23966,23967,23968,23969,23970,23971,23972,23973,23974,
91564 23975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986,
91565 23987,23988,23989,23990,23991,23992,23993,23994,23995,23996,23997,23998,
91566 23999,24000,24001,24002,24003,24004,24005,24006,24007,24008,24009,24010,
91567 24011,24012,24013,24014,24015,24016,24017,24018,24019,24020,24021,24022,
91568 24023,24024,24025,24026,24027,24028,24029,24030,24031,24032,24033,24034,
91569 24035,24036,24037,24038,24039,24040,24041,24042,24043,24044,24045,24046,
91570 24047,24048,24049,24050,24051,24052,24053,24054,24055,24056,24057,24058,
91571 24059,24060,24061,24062,24063,24064,24065,24066,24067,24068,24069,24070,
91572 24071,24072,24073,24074,24075,24076,24077,24078,24079,24080,24081,24082,
91573 24083,24084,24085,24086,24087,24088,24089,24090,24091,24092,24093,24094,
91574 24095,24096,24097,24098,24099,24100,24101,24102,24103,24104,24105,24106,
91575 24107,24108,24109,24110,24111,24112,24113,24114,24115,24116,24117,24118,
91576 24119,24120,24121,24122,24123,24124,24125,24126,24127,24128,24129,24130,
91577 24131,24132,24133,24134,24135,24136,24137,24138,24139,24140,24141,24142,
91578 24143,24144,24145,24146,24147,24148,24149,24150,24151,24152,24153,24154,
91579 24155,24156,24157,24158,24159,24160,24161,24162,24163,24164,24165,24166,
91580 24167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24178,
91581 24179,24180,24181,24182,24183,24184,24185,24186,24187,24188,24189,24190,
91582 24191,24192,24193,24194,24195,24196,24197,24198,24199,24200,24201,24202,
91583 24203,24204,24205,24206,24207,24208,24209,24210,24211,24212,24213,24214,
91584 24215,24216,24217,24218,24219,24220,24221,24222,24223,24224,24225,24226,
91585 24227,24228,24229,24230,24231,24232,24233,24234,24235,24236,24237,24238,
91586 24239,24240,24241,24242,24243,24244,24245,24246,24247,24248,24249,24250,
91587 24251,24252,24253,24254,24255,24256,24257,24258,24259,24260,24261,24262,
91588 24263,24264,24265,24266,24267,24268,24269,24270,24271,24272,24273,24274,
91589 24275,24276,24277,24278,24279,24280,24281,24282,24283,24284,24285,24286,
91590 24287,24288,24289,24290,24291,24292,24293,24294,24295,24296,24297,24298,
91591 24299,24300,24301,24302,24303,24304,24305,24306,24307,24308,24309,24310,
91592 24311,24312,24313,24314,24315,24316,24317,24318,24319,24320,24321,24322,
91593 24323,24324,24325,24326,24327,24328,24329,24330,24331,24332,24333,24334,
91594 24335,24336,24337,24338,24339,24340,24341,24342,24343,24344,24345,24346,
91595 24347,24348,24349,24350,24351,24352,24353,24354,24355,24356,24357,24358,
91596 24359,24360,24361,24362,24363,24364,24365,24366,24367,24368,24369,24370,
91597 24371,24372,24373,24374,24375,24376,24377,24378,24379,24380,24381,24382,
91598 24383,24384,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394,
91599 24395,24396,24397,24398,24399,24400,24401,24402,24403,24404,24405,24406,
91600 24407,24408,24409,24410,24411,24412,24413,24414,24415,24416,24417,24418,
91601 24419,24420,24421,24422,24423,24424,24425,24426,24427,24428,24429,24430,
91602 24431,24432,24433,24434,24435,24436,24437,24438,24439,24440,24441,24442,
91603 24443,24444,24445,24446,24447,24448,24449,24450,24451,24452,24453,24454,
91604 24455,24456,24457,24458,24459,24460,24461,24462,24463,24464,24465,24466,
91605 24467,24468,24469,24470,24471,24472,24473,24474,24475,24476,24477,24478,
91606 24479,24480,24481,24482,24483,24484,24485,24486,24487,24488,24489,24490,
91607 24491,24492,24493,24494,24495,24496,24497,24498,24499,24500,24501,24502,
91608 24503,24504,24505,24506,24507,24508,24509,24510,24511,24512,24513,24514,
91609 24515,24516,24517,24518,24519,24520,24521,24522,24523,24524,24525,24526,
91610 24527,24528,24529,24530,24531,24532,24533,24534,24535,24536,24537,24538,
91611 24539,24540,24541,24542,24543,24544,24545,24546,24547,24548,24549,24550,
91612 24551,24552,24553,24554,24555,24556,24557,24558,24559,24560,24561,24562,
91613 24563,24564,24565,24566,24567,24568,24569,24570,24571,24572,24573,24574,
91614 24575,24576,24577,24578,24579,24580,24581,24582,24583,24584,24585,24586,
91615 24587,24588,24589,24590,24591,24592,24593,24594,24595,24596,24597,24598,
91616 24599,24600,24601,24602,24603,24604,24605,24606,24607,24608,24609,24610,
91617 24611,24612,24613,24614,24615,24616,24617,24618,24619,24620,24621,24622,
91618 24623,24624,24625,24626,24627,24628,24629,24630,24631,24632,24633,24634,
91619 24635,24636,24637,24638,24639,24640,24641,24642,24643,24644,24645,24646,
91620 24647,24648,24649,24650,24651,24652,24653,24654,24655,24656,24657,24658,
91621 24659,24660,24661,24662,24663,24664,24665,24666,24667,24668,24669,24670,
91622 24671,24672,24673,24674,24675,24676,24677,24678,24679,24680,24681,24682,
91623 24683,24684,24685,24686,24687,24688,24689,24690,24691,24692,24693,24694,
91624 24695,24696,24697,24698,24699,24700,24701,24702,24703,24704,24705,24706,
91625 24707,24708,24709,24710,24711,24712,24713,24714,24715,24716,24717,24718,
91626 24719,24720,24721,24722,24723,24724,24725,24726,24727,24728,24729,24730,
91627 24731,24732,24733,24734,24735,24736,24737,24738,24739,24740,24741,24742,
91628 24743,24744,24745,24746,24747,24748,24749,24750,24751,24752,24753,24754,
91629 24755,24756,24757,24758,24759,24760,24761,24762,24763,24764,24765,24766,
91630 24767,24768,24769,24770,24771,24772,24773,24774,24775,24776,24777,24778,
91631 24779,24780,24781,24782,24783,24784,24785,24786,24787,24788,24789,24790,
91632 24791,24792,24793,24794,24795,24796,24797,24798,24799,24800,24801,24802,
91633 24803,24804,24805,24806,24807,24808,24809,24810,24811,24812,24813,24814,
91634 24815,24816,24817,24818,24819,24820,24821,24822,24823,24824,24825,24826,
91635 24827,24828,24829,24830,24831,24832,24833,24834,24835,24836,24837,24838,
91636 24839,24840,24841,24842,24843,24844,24845,24846,24847,24848,24849,24850,
91637 24851,24852,24853,24854,24855,24856,24857,24858,24859,24860,24861,24862,
91638 24863,24864,24865,24866,24867,24868,24869,24870,24871,24872,24873,24874,
91639 24875,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,
91640 24887,24888,24889,24890,24891,24892,24893,24894,24895,24896,24897,24898,
91641 24899,24900,24901,24902,24903,24904,24905,24906,24907,24908,24909,24910,
91642 24911,24912,24913,24914,24915,24916,24917,24918,24919,24920,24921,24922,
91643 24923,24924,24925,24926,24927,24928,24929,24930,24931,24932,24933,24934,
91644 24935,24936,24937,24938,24939,24940,24941,24942,24943,24944,24945,24946,
91645 24947,24948,24949,24950,24951,24952,24953,24954,24955,24956,24957,24958,
91646 24959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970,
91647 24971,24972,24973,24974,24975,24976,24977,24978,24979,24980,24981,24982,
91648 24983,24984,24985,24986,24987,24988,24989,24990,24991,24992,24993,24994,
91649 24995,24996,24997,24998,24999,25000,25001,25002,25003,25004,25005,25006,
91650 25007,25008,25009,25010,25011,25012,25013,25014,25015,25016,25017,25018,
91651 25019,25020,25021,25022,25023,25024,25025,25026,25027,25028,25029,25030,
91652 25031,25032,25033,25034,25035,25036,25037,25038,25039,25040,25041,25042,
91653 25043,25044,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054,
91654 25055,25056,25057,25058,25059,25060,25061,25062,25063,25064,25065,25066,
91655 25067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25077,25078,
91656 25079,25080,25081,25082,25083,25084,25085,25086,25087,25088,25089,25090,
91657 25091,25092,25093,25094,25095,25096,25097,25098,25099,25100,25101,25102,
91658 25103,25104,25105,25106,25107,25108,25109,25110,25111,25112,25113,25114,
91659 25115,25116,25117,25118,25119,25120,25121,25122,25123,25124,25125,25126,
91660 25127,25128,25129,25130,25131,25132,25133,25134,25135,25136,25137,25138,
91661 25139,25140,25141,25142,25143,25144,25145,25146,25147,25148,25149,25150,
91662 25151,25152,25153,25154,25155,25156,25157,25158,25159,25160,25161,25162,
91663 25163,25164,25165,25166,25167,25168,25169,25170,25171,25172,25173,25174,
91664 25175,25176,25177,25178,25179,25180,25181,25182,25183,25184,25185,25186,
91665 25187,25188,25189,25190,25191,25192,25193,25194,25195,25196,25197,25198,
91666 25199,25200,25201,25202,25203,25204,25205,25206,25207,25208,25209,25210,
91667 25211,25212,25213,25214,25215,25216,25217,25218,25219,25220,25221,25222,
91668 25223,25224,25225,25226,25227,25228,25229,25230,25231,25232,25233,25234,
91669 25235,25236,25237,25238,25239,25240,25241,25242,25243,25244,25245,25246,
91670 25247,25248,25249,25250,25251,25252,25253,25254,25255,25256,25257,25258,
91671 25259,25260,25261,25262,25263,25264,25265,25266,25267,25268,25269,25270,
91672 25271,25272,25273,25274,25275,25276,25277,25278,25279,25280,25281,25282,
91673 25283,25284,25285,25286,25287,25288,25289,25290,25291,25292,25293,25294,
91674 25295,25296,25297,25298,25299,25300,25301,25302,25303,25304,25305,25306,
91675 25307,25308,25309,25310,25311,25312,25313,25314,25315,25316,25317,25318,
91676 25319,25320,25321,25322,25323,25324,25325,25326,25327,25328,25329,25330,
91677 25331,25332,25333,25334,25335,25336,25337,25338,25339,25340,25341,25342,
91678 25343,25344,25345,25346,25347,25348,25349,25350,25351,25352,25353,25354,
91679 25355,25356,25357,25358,25359,25360,25361,25362,25363,25364,25365,25366,
91680 25367,25368,25369,25370,25371,25372,25373,25374,25375,25376,25377,25378,
91681 25379,25380,25381,25382,25383,25384,25385,25386,25387,25388,25389,25390,
91682 25391,25392,25393,25394,25395,25396,25397,25398,25399,25400,25401,25402,
91683 25403,25404,25405,25406,25407,25408,25409,25410,25411,25412,25413,25414,
91684 25415,25416,25417,25418,25419,25420,25421,25422,25423,25424,25425,25426,
91685 25427,25428,25429,25430,25431,25432,25433,25434,25435,25436,25437,25438,
91686 25439,25440,25441,25442,25443,25444,25445,25446,25447,25448,25449,25450,
91687 25451,25452,25453,25454,25455,25456,25457,25458,25459,25460,25461,25462,
91688 25463,25464,25465,25466,25467,25468,25469,25470,25471,25472,25473,25474,
91689 25475,25476,25477,25478,25479,25480,25481,25482,25483,25484,25485,25486,
91690 25487,25488,25489,25490,25491,25492,25493,25494,25495,25496,25497,25498,
91691 25499,25500,25501,25502,25503,25504,25505,25506,25507,25508,25509,25510,
91692 25511,25512,25513,25514,25515,25516,25517,25518,25519,25520,25521,25522,
91693 25523,25524,25525,25526,25527,25528,25529,25530,25531,25532,25533,25534,
91694 25535,25536,25537,25538,25539,25540,25541,25542,25543,25544,25545,25546,
91695 25547,25548,25549,25550,25551,25552,25553,25554,25555,25556,25557,25558,
91696 25559,25560,25561,25562,25563,25564,25565,25566,25567,25568,25569,25570,
91697 25571,25572,25573,25574,25575,25576,25577,25578,25579,25580,25581,25582,
91698 25583,25584,25585,25586,25587,25588,25589,25590,25591,25592,25593,25594,
91699 25595,25596,25597,25598,25599,25600,25601,25602,25603,25604,25605,25606,
91700 25607,25608,25609,25610,25611,25612,25613,25614,25615,25616,25617,25618,
91701 25619,25620,25621,25622,25623,25624,25625,25626,25627,25628,25629,25630,
91702 25631,25632,25633,25634,25635,25636,25637,25638,25639,25640,25641,25642,
91703 25643,25644,25645,25646,25647,25648,25649,25650,25651,25652,25653,25654,
91704 25655,25656,25657,25658,25659,25660,25661,25662,25663,25664,25665,25666,
91705 25667,25668,25669,25670,25671,25672,25673,25674,25675,25676,25677,25678,
91706 25679,25680,25681,25682,25683,25684,25685,25686,25687,25688,25689,25690,
91707 25691,25692,25693,25694,25695,25696,25697,25698,25699,25700,25701,25702,
91708 25703,25704,25705,25706,25707,25708,25709,25710,25711,25712,25713,25714,
91709 25715,25716,25717,25718,25719,25720,25721,25722,25723,25724,25725,25726,
91710 25727,25728,25729,25730,25731,25732,25733,25734,25735,25736,25737,25738,
91711 25739,25740,25741,25742,25743,25744,25745,25746,25747,25748,25749,25750,
91712 25751,25752,25753,25754,25755,25756,25757,25758,25759,25760,25761,25762,
91713 25763,25764,25765,25766,25767,25768,25769,25770,25771,25772,25773,25774,
91714 25775,25776,25777,25778,25779,25780,25781,25782,25783,25784,25785,25786,
91715 25787,25788,25789,25790,25791,25792,25793,25794,25795,25796,25797,25798,
91716 25799,25800,25801,25802,25803,25804,25805,25806,25807,25808,25809,25810,
91717 25811,25812,25813,25814,25815,25816,25817,25818,25819,25820,25821,25822,
91718 25823,25824,25825,25826,25827,25828,25829,25830,25831,25832,25833,25834,
91719 25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846,
91720 25847,25848,25849,25850,25851,25852,25853,25854,25855,25856,25857,25858,
91721 25859,25860,25861,25862,25863,25864,25865,25866,25867,25868,25869,25870,
91722 25871,25872,25873,25874,25875,25876,25877,25878,25879,25880,25881,25882,
91723 25883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25893,25894,
91724 25895,25896,25897,25898,25899,25900,25901,25902,25903,25904,25905,25906,
91725 25907,25908,25909,25910,25911,25912,25913,25914,25915,25916,25917,25918,
91726 25919,25920,25921,25922,25923,25924,25925,25926,25927,25928,25929,25930,
91727 25931,25932,25933,25934,25935,25936,25937,25938,25939,25940,25941,25942,
91728 25943,25944,25945,25946,25947,25948,25949,25950,25951,25952,25953,25954,
91729 25955,25956,25957,25958,25959,25960,25961,25962,25963,25964,25965,25966,
91730 25967,25968,25969,25970,25971,25972,25973,25974,25975,25976,25977,25978,
91731 25979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990,
91732 25991,25992,25993,25994,25995,25996,25997,25998,25999,26000,26001,26002,
91733 26003,26004,26005,26006,26007,26008,26009,26010,26011,26012,26013,26014,
91734 26015,26016,26017,26018,26019,26020,26021,26022,26023,26024,26025,26026,
91735 26027,26028,26029,26030,26031,26032,26033,26034,26035,26036,26037,26038,
91736 26039,26040,26041,26042,26043,26044,26045,26046,26047,26048,26049,26050,
91737 26051,26052,26053,26054,26055,26056,26057,26058,26059,26060,26061,26062,
91738 26063,26064,26065,26066,26067,26068,26069,26070,26071,26072,26073,26074,
91739 26075,26076,26077,26078,26079,26080,26081,26082,26083,26084,26085,26086,
91740 26087,26088,26089,26090,26091,26092,26093,26094,26095,26096,26097,26098,
91741 26099,26100,26101,26102,26103,26104,26105,26106,26107,26108,26109,26110,
91742 26111,26112,26113,26114,26115,26116,26117,26118,26119,26120,26121,26122,
91743 26123,26124,26125,26126,26127,26128,26129,26130,26131,26132,26133,26134,
91744 26135,26136,26137,26138,26139,26140,26141,26142,26143,26144,26145,26146,
91745 26147,26148,26149,26150,26151,26152,26153,26154,26155,26156,26157,26158,
91746 26159,26160,26161,26162,26163,26164,26165,26166,26167,26168,26169,26170,
91747 26171,26172,26173,26174,26175,26176,26177,26178,26179,26180,26181,26182,
91748 26183,26184,26185,26186,26187,26188,26189,26190,26191,26192,26193,26194,
91749 26195,26196,26197,26198,26199,26200,26201,26202,26203,26204,26205,26206,
91750 26207,26208,26209,26210,26211,26212,26213,26214,26215,26216,26217,26218,
91751 26219,26220,26221,26222,26223,26224,26225,26226,26227,26228,26229,26230,
91752 26231,26232,26233,26234,26235,26236,26237,26238,26239,26240,26241,26242,
91753 26243,26244,26245,26246,26247,26248,26249,26250,26251,26252,26253,26254,
91754 26255,26256,26257,26258,26259,26260,26261,26262,26263,26264,26265,26266,
91755 26267,26268,26269,26270,26271,26272,26273,26274,26275,26276,26277,26278,
91756 26279,26280,26281,26282,26283,26284,26285,26286,26287,26288,26289,26290,
91757 26291,26292,26293,26294,26295,26296,26297,26298,26299,26300,26301,26302,
91758 26303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314,
91759 26315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326,
91760 26327,26328,26329,26330,26331,26332,26333,26334,26335,26336,26337,26338,
91761 26339,26340,26341,26342,26343,26344,26345,26346,26347,26348,26349,26350,
91762 26351,26352,26353,26354,26355,26356,26357,26358,26359,26360,26361,26362,
91763 26363,26364,26365,26366,26367,26368,26369,26370,26371,26372,26373,26374,
91764 26375,26376,26377,26378,26379,26380,26381,26382,26383,26384,26385,26386,
91765 26387,26388,26389,26390,26391,26392,26393,26394,26395,26396,26397,26398,
91766 26399,26400,26401,26402,26403,26404,26405,26406,26407,26408,26409,26410,
91767 26411,26412,26413,26414,26415,26416,26417,26418,26419,26420,26421,26422,
91768 26423,26424,26425,26426,26427,26428,26429,26430,26431,26432,26433,26434,
91769 26435,26436,26437,26438,26439,26440,26441,26442,26443,26444,26445,26446,
91770 26447,26448,26449,26450,26451,26452,26453,26454,26455,26456,26457,26458,
91771 26459,26460,26461,26462,26463,26464,26465,26466,26467,26468,26469,26470,
91772 26471,26472,26473,26474,26475,26476,26477,26478,26479,26480,26481,26482,
91773 26483,26484,26485,26486,26487,26488,26489,26490,26491,26492,26493,26494,
91774 26495,26496,26497,26498,26499,26500,26501,26502,26503,26504,26505,26506,
91775 26507,26508,26509,26510,26511,26512,26513,26514,26515,26516,26517,26518,
91776 26519,26520,26521,26522,26523,26524,26525,26526,26527,26528,26529,26530,
91777 26531,26532,26533,26534,26535,26536,26537,26538,26539,26540,26541,26542,
91778 26543,26544,26545,26546,26547,26548,26549,26550,26551,26552,26553,26554,
91779 26555,26556,26557,26558,26559,26560,26561,26562,26563,26564,26565,26566,
91780 26567,26568,26569,26570,26571,26572,26573,26574,26575,26576,26577,26578,
91781 26579,26580,26581,26582,26583,26584,26585,26586,26587,26588,26589,26590,
91782 26591,26592,26593,26594,26595,26596,26597,26598,26599,26600,26601,26602,
91783 26603,26604,26605,26606,26607,26608,26609,26610,26611,26612,26613,26614,
91784 26615,26616,26617,26618,26619,26620,26621,26622,26623,26624,26625,26626,
91785 26627,26628,26629,26630,26631,26632,26633,26634,26635,26636,26637,26638,
91786 26639,26640,26641,26642,26643,26644,26645,26646,26647,26648,26649,26650,
91787 26651,26652,26653,26654,26655,26656,26657,26658,26659,26660,26661,26662,
91788 26663,26664,26665,26666,26667,26668,26669,26670,26671,26672,26673,26674,
91789 26675,26676,26677,26678,26679,26680,26681,26682,26683,26684,26685,26686,
91790 26687,26688,26689,26690,26691,26692,26693,26694,26695,26696,26697,26698,
91791 26699,26700,26701,26702,26703,26704,26705,26706,26707,26708,26709,26710,
91792 26711,26712,26713,26714,26715,26716,26717,26718,26719,26720,26721,26722,
91793 26723,26724,26725,26726,26727,26728,26729,26730,26731,26732,26733,26734,
91794 26735,26736,26737,26738,26739,26740,26741,26742,26743,26744,26745,26746,
91795 26747,26748,26749,26750,26751,26752,26753,26754,26755,26756,26757,26758,
91796 26759,26760,26761,26762,26763,26764,26765,26766,26767,26768,26769,26770,
91797 26771,26772,26773,26774,26775,26776,26777,26778,26779,26780,26781,26782,
91798 26783,26784,26785,26786,26787,26788,26789,26790,26791,26792,26793,26794,
91799 26795,26796,26797,26798,26799,26800,26801,26802,26803,26804,26805,26806,
91800 26807,26808,26809,26810,26811,26812,26813,26814,26815,26816,26817,26818,
91801 26819,26820,26821,26822,26823,26824,26825,26826,26827,26828,26829,26830,
91802 26831,26832,26833,26834,26835,26836,26837,26838,26839,26840,26841,26842,
91803 26843,26844,26845,26846,26847,26848,26849,26850,26851,26852,26853,26854,
91804 26855,26856,26857,26858,26859,26860,26861,26862,26863,26864,26865,26866,
91805 26867,26868,26869,26870,26871,26872,26873,26874,26875,26876,26877,26878,
91806 26879,26880,26881,26882,26883,26884,26885,26886,26887,26888,26889,26890,
91807 26891,26892,26893,26894,26895,26896,26897,26898,26899,26900,26901,26902,
91808 26903,26904,26905,26906,26907,26908,26909,26910,26911,26912,26913,26914,
91809 26915,26916,26917,26918,26919,26920,26921,26922,26923,26924,26925,26926,
91810 26927,26928,26929,26930,26931,26932,26933,26934,26935,26936,26937,26938,
91811 26939,26940,26941,26942,26943,26944,26945,26946,26947,26948,26949,26950,
91812 26951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962,
91813 26963,26964,26965,26966,26967,26968,26969,26970,26971,26972,26973,26974,
91814 26975,26976,26977,26978,26979,26980,26981,26982,26983,26984,26985,26986,
91815 26987,26988,26989,26990,26991,26992,26993,26994,26995,26996,26997,26998,
91816 26999,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,
91817 27011,27012,27013,27014,27015,27016,27017,27018,27019,27020,27021,27022,
91818 27023,27024,27025,27026,27027,27028,27029,27030,27031,27032,27033,27034,
91819 27035,27036,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046,
91820 27047,27048,27049,27050,27051,27052,27053,27054,27055,27056,27057,27058,
91821 27059,27060,27061,27062,27063,27064,27065,27066,27067,27068,27069,27070,
91822 27071,27072,27073,27074,27075,27076,27077,27078,27079,27080,27081,27082,
91823 27083,27084,27085,27086,27087,27088,27089,27090,27091,27092,27093,27094,
91824 27095,27096,27097,27098,27099,27100,27101,27102,27103,27104,27105,27106,
91825 27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27117,27118,
91826 27119,27120,27121,27122,27123,27124,27125,27126,27127,27128,27129,27130,
91827 27131,27132,27133,27134,27135,27136,27137,27138,27139,27140,27141,27142,
91828 27143,27144,27145,27146,27147,27148,27149,27150,27151,27152,27153,27154,
91829 27155,27156,27157,27158,27159,27160,27161,27162,27163,27164,27165,27166,
91830 27167,27168,27169,27170,27171,27172,27173,27174,27175,27176,27177,27178,
91831 27179,27180,27181,27182,27183,27184,27185,27186,27187,27188,27189,27190,
91832 27191,27192,27193,27194,27195,27196,27197,27198,27199,27200,27201,27202,
91833 27203,27204,27205,27206,27207,27208,27209,27210,27211,27212,27213,27214,
91834 27215,27216,27217,27218,27219,27220,27221,27222,27223,27224,27225,27226,
91835 27227,27228,27229,27230,27231,27232,27233,27234,27235,27236,27237,27238,
91836 27239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27249,27250,
91837 27251,27252,27253,27254,27255,27256,27257,27258,27259,27260,27261,27262,
91838 27263,27264,27265,27266,27267,27268,27269,27270,27271,27272,27273,27274,
91839 27275,27276,27277,27278,27279,27280,27281,27282,27283,27284,27285,27286,
91840 27287,27288,27289,27290,27291,27292,27293,27294,27295,27296,27297,27298,
91841 27299,27300,27301,27302,27303,27304,27305,27306,27307,27308,27309,27310,
91842 27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,
91843 27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,
91844 27335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346,
91845 27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,
91846 27359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370,
91847 27371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382,
91848 27383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394,
91849 27395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406,
91850 27407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418,
91851 27419,27420,27421,27422,27423,27424,27425,27426,27427,27428,27429,27430,
91852 27431,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27442,
91853 27443,27444,27445,27446,27447,27448,27449,27450,27451,27452,27453,27454,
91854 27455,27456,27457,27458,27459,27460,27461,27462,27463,27464,27465,27466,
91855 27467,27468,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478,
91856 27479,27480,27481,27482,27483,27484,27485,27486,27487,27488,27489,27490,
91857 27491,27492,27493,27494,27495,27496,27497,27498,27499,27500,27501,27502,
91858 27503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27513,27514,
91859 27515,27516,27517,27518,27519,27520,27521,27522,27523,27524,27525,27526,
91860 27527,27528,27529,27530,27531,27532,27533,27534,27535,27536,27537,27538,
91861 27539,27540,27541,27542,27543,27544,27545,27546,27547,27548,27549,27550,
91862 27551,27552,27553,27554,27555,27556,27557,27558,27559,27560,27561,27562,
91863 27563,27564,27565,27566,27567,27568,27569,27570,27571,27572,27573,27574,
91864 27575,27576,27577,27578,27579,27580,27581,27582,27583,27584,27585,27586,
91865 27587,27588,27589,27590,27591,27592,27593,27594,27595,27596,27597,27598,
91866 27599,27600,27601,27602,27603,27604,27605,27606,27607,27608,27609,27610,
91867 27611,27612,27613,27614,27615,27616,27617,27618,27619,27620,27621,27622,
91868 27623,27624,27625,27626,27627,27628,27629,27630,27631,27632,27633,27634,
91869 27635,27636,27637,27638,27639,27640,27641,27642,27643,27644,27645,27646,
91870 27647,27648,27649,27650,27651,27652,27653,27654,27655,27656,27657,27658,
91871 27659,27660,27661,27662,27663,27664,27665,27666,27667,27668,27669,27670,
91872 27671,27672,27673,27674,27675,27676,27677,27678,27679,27680,27681,27682,
91873 27683,27684,27685,27686,27687,27688,27689,27690,27691,27692,27693,27694,
91874 27695,27696,27697,27698,27699,27700,27701,27702,27703,27704,27705,27706,
91875 27707,27708,27709,27710,27711,27712,27713,27714,27715,27716,27717,27718,
91876 27719,27720,27721,27722,27723,27724,27725,27726,27727,27728,27729,27730,
91877 27731,27732,27733,27734,27735,27736,27737,27738,27739,27740,27741,27742,
91878 27743,27744,27745,27746,27747,27748,27749,27750,27751,27752,27753,27754,
91879 27755,27756,27757,27758,27759,27760,27761,27762,27763,27764,27765,27766,
91880 27767,27768,27769,27770,27771,27772,27773,27774,27775,27776,27777,27778,
91881 27779,27780,27781,27782,27783,27784,27785,27786,27787,27788,27789,27790,
91882 27791,27792,27793,27794,27795,27796,27797,27798,27799,27800,27801,27802,
91883 27803,27804,27805,27806,27807,27808,27809,27810,27811,27812,27813,27814,
91884 27815,27816,27817,27818,27819,27820,27821,27822,27823,27824,27825,27826,
91885 27827,27828,27829,27830,27831,27832,27833,27834,27835,27836,27837,27838,
91886 27839,27840,27841,27842,27843,27844,27845,27846,27847,27848,27849,27850,
91887 27851,27852,27853,27854,27855,27856,27857,27858,27859,27860,27861,27862,
91888 27863,27864,27865,27866,27867,27868,27869,27870,27871,27872,27873,27874,
91889 27875,27876,27877,27878,27879,27880,27881,27882,27883,27884,27885,27886,
91890 27887,27888,27889,27890,27891,27892,27893,27894,27895,27896,27897,27898,
91891 27899,27900,27901,27902,27903,27904,27905,27906,27907,27908,27909,27910,
91892 27911,27912,27913,27914,27915,27916,27917,27918,27919,27920,27921,27922,
91893 27923,27924,27925,27926,27927,27928,27929,27930,27931,27932,27933,27934,
91894 27935,27936,27937,27938,27939,27940,27941,27942,27943,27944,27945,27946,
91895 27947,27948,27949,27950,27951,27952,27953,27954,27955,27956,27957,27958,
91896 27959,27960,27961,27962,27963,27964,27965,27966,27967,27968,27969,27970,
91897 27971,27972,27973,27974,27975,27976,27977,27978,27979,27980,27981,27982,
91898 27983,27984,27985,27986,27987,27988,27989,27990,27991,27992,27993,27994,
91899 27995,27996,27997,27998,27999,28000,28001,28002,28003,28004,28005,28006,
91900 28007,28008,28009,28010,28011,28012,28013,28014,28015,28016,28017,28018,
91901 28019,28020,28021,28022,28023,28024,28025,28026,28027,28028,28029,28030,
91902 28031,28032,28033,28034,28035,28036,28037,28038,28039,28040,28041,28042,
91903 28043,28044,28045,28046,28047,28048,28049,28050,28051,28052,28053,28054,
91904 28055,28056,28057,28058,28059,28060,28061,28062,28063,28064,28065,28066,
91905 28067,28068,28069,28070,28071,28072,28073,28074,28075,28076,28077,28078,
91906 28079,28080,28081,28082,28083,28084,28085,28086,28087,28088,28089,28090,
91907 28091,28092,28093,28094,28095,28096,28097,28098,28099,28100,28101,28102,
91908 28103,28104,28105,28106,28107,28108,28109,28110,28111,28112,28113,28114,
91909 28115,28116,28117,28118,28119,28120,28121,28122,28123,28124,28125,28126,
91910 28127,28128,28129,28130,28131,28132,28133,28134,28135,28136,28137,28138,
91911 28139,28140,28141,28142,28143,28144,28145,28146,28147,28148,28149,28150,
91912 28151,28152,28153,28154,28155,28156,28157,28158,28159,28160,28161,28162,
91913 28163,28164,28165,28166,28167,28168,28169,28170,28171,28172,28173,28174,
91914 28175,28176,28177,28178,28179,28180,28181,28182,28183,28184,28185,28186,
91915 28187,28188,28189,28190,28191,28192,28193,28194,28195,28196,28197,28198,
91916 28199,28200,28201,28202,28203,28204,28205,28206,28207,28208,28209,28210,
91917 28211,28212,28213,28214,28215,28216,28217,28218,28219,28220,28221,28222,
91918 28223,28224,28225,28226,28227,28228,28229,28230,28231,28232,28233,28234,
91919 28235,28236,28237,28238,28239,28240,28241,28242,28243,28244,28245,28246,
91920 28247,28248,28249,28250,28251,28252,28253,28254,28255,28256,28257,28258,
91921 28259,28260,28261,28262,28263,28264,28265,28266,28267,28268,28269,28270,
91922 28271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,
91923 28283,28284,28285,28286,28287,28288,28289,28290,28291,28292,28293,28294,
91924 28295,28296,28297,28298,28299,28300,28301,28302,28303,28304,28305,28306,
91925 28307,28308,28309,28310,28311,28312,28313,28314,28315,28316,28317,28318,
91926 28319,28320,28321,28322,28323,28324,28325,28326,28327,28328,28329,28330,
91927 28331,28332,28333,28334,28335,28336,28337,28338,28339,28340,28341,28342,
91928 28343,28344,28345,28346,28347,28348,28349,28350,28351,28352,28353,28354,
91929 28355,28356,28357,28358,28359,28360,28361,28362,28363,28364,28365,28366,
91930 28367,28368,28369,28370,28371,28372,28373,28374,28375,28376,28377,28378,
91931 28379,28380,28381,28382,28383,28384,28385,28386,28387,28388,28389,28390,
91932 28391,28392,28393,28394,28395,28396,28397,28398,28399,28400,28401,28402,
91933 28403,28404,28405,28406,28407,28408,28409,28410,28411,28412,28413,28414,
91934 28415,28416,28417,28418,28419,28420,28421,28422,28423,28424,28425,28426,
91935 28427,28428,28429,28430,28431,28432,28433,28434,28435,28436,28437,28438,
91936 28439,28440,28441,28442,28443,28444,28445,28446,28447,28448,28449,28450,
91937 28451,28452,28453,28454,28455,28456,28457,28458,28459,28460,28461,28462,
91938 28463,28464,28465,28466,28467,28468,28469,28470,28471,28472,28473,28474,
91939 28475,28476,28477,28478,28479,28480,28481,28482,28483,28484,28485,28486,
91940 28487,28488,28489,28490,28491,28492,28493,28494,28495,28496,28497,28498,
91941 28499,28500,28501,28502,28503,28504,28505,28506,28507,28508,28509,28510,
91942 28511,28512,28513,28514,28515,28516,28517,28518,28519,28520,28521,28522,
91943 28523,28524,28525,28526,28527,28528,28529,28530,28531,28532,28533,28534,
91944 28535,28536,28537,28538,28539,28540,28541,28542,28543,28544,28545,28546,
91945 28547,28548,28549,28550,28551,28552,28553,28554,28555,28556,28557,28558,
91946 28559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570,
91947 28571,28572,28573,28574,28575,28576,28577,28578,28579,28580,28581,28582,
91948 28583,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594,
91949 28595,28596,28597,28598,28599,28600,28601,28602,28603,28604,28605,28606,
91950 28607,28608,28609,28610,28611,28612,28613,28614,28615,28616,28617,28618,
91951 28619,28620,28621,28622,28623,28624,28625,28626,28627,28628,28629,28630,
91952 28631,28632,28633,28634,28635,28636,28637,28638,28639,28640,28641,28642,
91953 28643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28654,
91954 28655,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666,
91955 28667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678,
91956 28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28689,28690,
91957 28691,28692,28693,28694,28695,28696,28697,28698,28699,28700,28701,28702,
91958 28703,28704,28705,28706,28707,28708,28709,28710,28711,28712,28713,28714,
91959 28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28725,28726,
91960 28727,28728,28729,28730,28731,28732,28733,28734,28735,28736,28737,28738,
91961 28739,28740,28741,28742,28743,28744,28745,28746,28747,28748,28749,28750,
91962 28751,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762,
91963 28763,28764,28765,28766,28767,28768,28769,28770,28771,28772,28773,28774,
91964 28775,28776,28777,28778,28779,28780,28781,28782,28783,28784,28785,28786,
91965 28787,28788,28789,28790,28791,28792,28793,28794,28795,28796,28797,28798,
91966 28799,28800,28801,28802,28803,28804,28805,28806,28807,28808,28809,28810,
91967 28811,28812,28813,28814,28815,28816,28817,28818,28819,28820,28821,28822,
91968 28823,28824,28825,28826,28827,28828,28829,28830,28831,28832,28833,28834,
91969 28835,28836,28837,28838,28839,28840,28841,28842,28843,28844,28845,28846,
91970 28847,28848,28849,28850,28851,28852,28853,28854,28855,28856,28857,28858,
91971 28859,28860,28861,28862,28863,28864,28865,28866,28867,28868,28869,28870,
91972 28871,28872,28873,28874,28875,28876,28877,28878,28879,28880,28881,28882,
91973 28883,28884,28885,28886,28887,28888,28889,28890,28891,28892,28893,28894,
91974 28895,28896,28897,28898,28899,28900,28901,28902,28903,28904,28905,28906,
91975 28907,28908,28909,28910,28911,28912,28913,28914,28915,28916,28917,28918,
91976 28919,28920,28921,28922,28923,28924,28925,28926,28927,28928,28929,28930,
91977 28931,28932,28933,28934,28935,28936,28937,28938,28939,28940,28941,28942,
91978 28943,28944,28945,28946,28947,28948,28949,28950,28951,28952,28953,28954,
91979 28955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28966,
91980 28967,28968,28969,28970,28971,28972,28973,28974,28975,28976,28977,28978,
91981 28979,28980,28981,28982,28983,28984,28985,28986,28987,28988,28989,28990,
91982 28991,28992,28993,28994,28995,28996,28997,28998,28999,29000,29001,29002,
91983 29003,29004,29005,29006,29007,29008,29009,29010,29011,29012,29013,29014,
91984 29015,29016,29017,29018,29019,29020,29021,29022,29023,29024,29025,29026,
91985 29027,29028,29029,29030,29031,29032,29033,29034,29035,29036,29037,29038,
91986 29039,29040,29041,29042,29043,29044,29045,29046,29047,29048,29049,29050,
91987 29051,29052,29053,29054,29055,29056,29057,29058,29059,29060,29061,29062,
91988 29063,29064,29065,29066,29067,29068,29069,29070,29071,29072,29073,29074,
91989 29075,29076,29077,29078,29079,29080,29081,29082,29083,29084,29085,29086,
91990 29087,29088,29089,29090,29091,29092,29093,29094,29095,29096,29097,29098,
91991 29099,29100,29101,29102,29103,29104,29105,29106,29107,29108,29109,29110,
91992 29111,29112,29113,29114,29115,29116,29117,29118,29119,29120,29121,29122,
91993 29123,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29134,
91994 29135,29136,29137,29138,29139,29140,29141,29142,29143,29144,29145,29146,
91995 29147,29148,29149,29150,29151,29152,29153,29154,29155,29156,29157,29158,
91996 29159,29160,29161,29162,29163,29164,29165,29166,29167,29168,29169,29170,
91997 29171,29172,29173,29174,29175,29176,29177,29178,29179,29180,29181,29182,
91998 29183,29184,29185,29186,29187,29188,29189,29190,29191,29192,29193,29194,
91999 29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206,
92000 29207,29208,29209,29210,29211,29212,29213,29214,29215,29216,29217,29218,
92001 29219,29220,29221,29222,29223,29224,29225,29226,29227,29228,29229,29230,
92002 29231,29232,29233,29234,29235,29236,29237,29238,29239,29240,29241,29242,
92003 29243,29244,29245,29246,29247,29248,29249,29250,29251,29252,29253,29254,
92004 29255,29256,29257,29258,29259,29260,29261,29262,29263,29264,29265,29266,
92005 29267,29268,29269,29270,29271,29272,29273,29274,29275,29276,29277,29278,
92006 29279,29280,29281,29282,29283,29284,29285,29286,29287,29288,29289,29290,
92007 29291,29292,29293,29294,29295,29296,29297,29298,29299,29300,29301,29302,
92008 29303,29304,29305,29306,29307,29308,29309,29310,29311,29312,29313,29314,
92009 29315,29316,29317,29318,29319,29320,29321,29322,29323,29324,29325,29326,
92010 29327,29328,29329,29330,29331,29332,29333,29334,29335,29336,29337,29338,
92011 29339,29340,29341,29342,29343,29344,29345,29346,29347,29348,29349,29350,
92012 29351,29352,29353,29354,29355,29356,29357,29358,29359,29360,29361,29362,
92013 29363,29364,29365,29366,29367,29368,29369,29370,29371,29372,29373,29374,
92014 29375,29376,29377,29378,29379,29380,29381,29382,29383,29384,29385,29386,
92015 29387,29388,29389,29390,29391,29392,29393,29394,29395,29396,29397,29398,
92016 29399,29400,29401,29402,29403,29404,29405,29406,29407,29408,29409,29410,
92017 29411,29412,29413,29414,29415,29416,29417,29418,29419,29420,29421,29422,
92018 29423,29424,29425,29426,29427,29428,29429,29430,29431,29432,29433,29434,
92019 29435,29436,29437,29438,29439,29440,29441,29442,29443,29444,29445,29446,
92020 29447,29448,29449,29450,29451,29452,29453,29454,29455,29456,29457,29458,
92021 29459,29460,29461,29462,29463,29464,29465,29466,29467,29468,29469,29470,
92022 29471,29472,29473,29474,29475,29476,29477,29478,29479,29480,29481,29482,
92023 29483,29484,29485,29486,29487,29488,29489,29490,29491,29492,29493,29494,
92024 29495,29496,29497,29498,29499,29500,29501,29502,29503,29504,29505,29506,
92025 29507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29517,29518,
92026 29519,29520,29521,29522,29523,29524,29525,29526,29527,29528,29529,29530,
92027 29531,29532,29533,29534,29535,29536,29537,29538,29539,29540,29541,29542,
92028 29543,29544,29545,29546,29547,29548,29549,29550,29551,29552,29553,29554,
92029 29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29566,
92030 29567,29568,29569,29570,29571,29572,29573,29574,29575,29576,29577,29578,
92031 29579,29580,29581,29582,29583,29584,29585,29586,29587,29588,29589,29590,
92032 29591,29592,29593,29594,29595,29596,29597,29598,29599,29600,29601,29602,
92033 29603,29604,29605,29606,29607,29608,29609,29610,29611,29612,29613,29614,
92034 29615,29616,29617,29618,29619,29620,29621,29622,29623,29624,29625,29626,
92035 29627,29628,29629,29630,29631,29632,29633,29634,29635,29636,29637,29638,
92036 29639,29640,29641,29642,29643,29644,29645,29646,29647,29648,29649,29650,
92037 29651,29652,29653,29654,29655,29656,29657,29658,29659,29660,29661,29662,
92038 29663,29664,29665,29666,29667,29668,29669,29670,29671,29672,29673,29674,
92039 29675,29676,29677,29678,29679,29680,29681,29682,29683,29684,29685,29686,
92040 29687,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698,
92041 29699,29700,29701,29702,29703,29704,29705,29706,29707,29708,29709,29710,
92042 29711,29712,29713,29714,29715,29716,29717,29718,29719,29720,29721,29722,
92043 29723,29724,29725,29726,29727,29728,29729,29730,29731,29732,29733,29734,
92044 29735,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29746,
92045 29747,29748,29749,29750,29751,29752,29753,29754,29755,29756,29757,29758,
92046 29759,29760,29761,29762,29763,29764,29765,29766,29767,29768,29769,29770,
92047 29771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29781,29782,
92048 29783,29784,29785,29786,29787,29788,29789,29790,29791,29792,29793,29794,
92049 29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29805,29806,
92050 29807,29808,29809,29810,29811,29812,29813,29814,29815,29816,29817,29818,
92051 29819,29820,29821,29822,29823,29824,29825,29826,29827,29828,29829,29830,
92052 29831,29832,29833,29834,29835,29836,29837,29838,29839,29840,29841,29842,
92053 29843,29844,29845,29846,29847,29848,29849,29850,29851,29852,29853,29854,
92054 29855,29856,29857,29858,29859,29860,29861,29862,29863,29864,29865,29866,
92055 29867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878,
92056 29879,29880,29881,29882,29883,29884,29885,29886,29887,29888,29889,29890,
92057 29891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902,
92058 29903,29904,29905,29906,29907,29908,29909,29910,29911,29912,29913,29914,
92059 29915,29916,29917,29918,29919,29920,29921,29922,29923,29924,29925,29926,
92060 29927,29928,29929,29930,29931,29932,29933,29934,29935,29936,29937,29938,
92061 29939,29940,29941,29942,29943,29944,29945,29946,29947,29948,29949,29950,
92062 29951,29952,29953,29954,29955,29956,29957,29958,29959,29960,29961,29962,
92063 29963,29964,29965,29966,29967,29968,29969,29970,29971,29972,29973,29974,
92064 29975,29976,29977,29978,29979,29980,29981,29982,29983,29984,29985,29986,
92065 29987,29988,29989,29990,29991,29992,29993,29994,29995,29996,29997,29998,
92066 29999,30000,30001,30002,30003,30004,30005,30006,30007,30008,30009,30010,
92067 30011,30012,30013,30014,30015,30016,30017,30018,30019,30020,30021,30022,
92068 30023,30024,30025,30026,30027,30028,30029,30030,30031,30032,30033,30034,
92069 30035,30036,30037,30038,30039,30040,30041,30042,30043,30044,30045,30046,
92070 30047,30048,30049,30050,30051,30052,30053,30054,30055,30056,30057,30058,
92071 30059,30060,30061,30062,30063,30064,30065,30066,30067,30068,30069,30070,
92072 30071,30072,30073,30074,30075,30076,30077,30078,30079,30080,30081,30082,
92073 30083,30084,30085,30086,30087,30088,30089,30090,30091,30092,30093,30094,
92074 30095,30096,30097,30098,30099,30100,30101,30102,30103,30104,30105,30106,
92075 30107,30108,30109,30110,30111,30112,30113,30114,30115,30116,30117,30118,
92076 30119,30120,30121,30122,30123,30124,30125,30126,30127,30128,30129,30130,
92077 30131,30132,30133,30134,30135,30136,30137,30138,30139,30140,30141,30142,
92078 30143,30144,30145,30146,30147,30148,30149,30150,30151,30152,30153,30154,
92079 30155,30156,30157,30158,30159,30160,30161,30162,30163,30164,30165,30166,
92080 30167,30168,30169,30170,30171,30172,30173,30174,30175,30176,30177,30178,
92081 30179,30180,30181,30182,30183,30184,30185,30186,30187,30188,30189,30190,
92082 30191,30192,30193,30194,30195,30196,30197,30198,30199,30200,30201,30202,
92083 30203,30204,30205,30206,30207,30208,30209,30210,30211,30212,30213,30214,
92084 30215,30216,30217,30218,30219,30220,30221,30222,30223,30224,30225,30226,
92085 30227,30228,30229,30230,30231,30232,30233,30234,30235,30236,30237,30238,
92086 30239,30240,30241,30242,30243,30244,30245,30246,30247,30248,30249,30250,
92087 30251,30252,30253,30254,30255,30256,30257,30258,30259,30260,30261,30262,
92088 30263,30264,30265,30266,30267,30268,30269,30270,30271,30272,30273,30274,
92089 30275,30276,30277,30278,30279,30280,30281,30282,30283,30284,30285,30286,
92090 30287,30288,30289,30290,30291,30292,30293,30294,30295,30296,30297,30298,
92091 30299,30300,30301,30302,30303,30304,30305,30306,30307,30308,30309,30310,
92092 30311,30312,30313,30314,30315,30316,30317,30318,30319,30320,30321,30322,
92093 30323,30324,30325,30326,30327,30328,30329,30330,30331,30332,30333,30334,
92094 30335,30336,30337,30338,30339,30340,30341,30342,30343,30344,30345,30346,
92095 30347,30348,30349,30350,30351,30352,30353,30354,30355,30356,30357,30358,
92096 30359,30360,30361,30362,30363,30364,30365,30366,30367,30368,30369,30370,
92097 30371,30372,30373,30374,30375,30376,30377,30378,30379,30380,30381,30382,
92098 30383,30384,30385,30386,30387,30388,30389,30390,30391,30392,30393,30394,
92099 30395,30396,30397,30398,30399,30400,30401,30402,30403,30404,30405,30406,
92100 30407,30408,30409,30410,30411,30412,30413,30414,30415,30416,30417,30418,
92101 30419,30420,30421,30422,30423,30424,30425,30426,30427,30428,30429,30430,
92102 30431,30432,30433,30434,30435,30436,30437,30438,30439,30440,30441,30442,
92103 30443,30444,30445,30446,30447,30448,30449,30450,30451,30452,30453,30454,
92104 30455,30456,30457,30458,30459,30460,30461,30462,30463,30464,30465,30466,
92105 30467,30468,30469,30470,30471,30472,30473,30474,30475,30476,30477,30478,
92106 30479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30489,30490,
92107 30491,30492,30493,30494,30495,30496,30497,30498,30499,30500,30501,30502,
92108 30503,30504,30505,30506,30507,30508,30509,30510,30511,30512,30513,30514,
92109 30515,30516,30517,30518,30519,30520,30521,30522,30523,30524,30525,30526,
92110 30527,30528,30529,30530,30531,30532,30533,30534,30535,30536,30537,30538,
92111 30539,30540,30541,30542,30543,30544,30545,30546,30547,30548,30549,30550,
92112 30551,30552,30553,30554,30555,30556,30557,30558,30559,30560,30561,30562,
92113 30563,30564,30565,30566,30567,30568,30569,30570,30571,30572,30573,30574,
92114 30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30585,30586,
92115 30587,30588,30589,30590,30591,30592,30593,30594,30595,30596,30597,30598,
92116 30599,30600,30601,30602,30603,30604,30605,30606,30607,30608,30609,30610,
92117 30611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622,
92118 30623,30624,30625,30626,30627,30628,30629,30630,30631,30632,30633,30634,
92119 30635,30636,30637,30638,30639,30640,30641,30642,30643,30644,30645,30646,
92120 30647,30648,30649,30650,30651,30652,30653,30654,30655,30656,30657,30658,
92121 30659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30669,30670,
92122 30671,30672,30673,30674,30675,30676,30677,30678,30679,30680,30681,30682,
92123 30683,30684,30685,30686,30687,30688,30689,30690,30691,30692,30693,30694,
92124 30695,30696,30697,30698,30699,30700,30701,30702,30703,30704,30705,30706,
92125 30707,30708,30709,30710,30711,30712,30713,30714,30715,30716,30717,30718,
92126 30719,30720,30721,30722,30723,30724,30725,30726,30727,30728,30729,30730,
92127 30731,30732,30733,30734,30735,30736,30737,30738,30739,30740,30741,30742,
92128 30743,30744,30745,30746,30747,30748,30749,30750,30751,30752,30753,30754,
92129 30755,30756,30757,30758,30759,30760,30761,30762,30763,30764,30765,30766,
92130 30767,30768,30769,30770,30771,30772,30773,30774,30775,30776,30777,30778,
92131 30779,30780,30781,30782,30783,30784,30785,30786,30787,30788,30789,30790,
92132 30791,30792,30793,30794,30795,30796,30797,30798,30799,30800,30801,30802,
92133 30803,30804,30805,30806,30807,30808,30809,30810,30811,30812,30813,30814,
92134 30815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30826,
92135 30827,30828,30829,30830,30831,30832,30833,30834,30835,30836,30837,30838,
92136 30839,30840,30841,30842,30843,30844,30845,30846,30847,30848,30849,30850,
92137 30851,30852,30853,30854,30855,30856,30857,30858,30859,30860,30861,30862,
92138 30863,30864,30865,30866,30867,30868,30869,30870,30871,30872,30873,30874,
92139 30875,30876,30877,30878,30879,30880,30881,30882,30883,30884,30885,30886,
92140 30887,30888,30889,30890,30891,30892,30893,30894,30895,30896,30897,30898,
92141 30899,30900,30901,30902,30903,30904,30905,30906,30907,30908,30909,30910,
92142 30911,30912,30913,30914,30915,30916,30917,30918,30919,30920,30921,30922,
92143 30923,30924,30925,30926,30927,30928,30929,30930,30931,30932,30933,30934,
92144 30935,30936,30937,30938,30939,30940,30941,30942,30943,30944,30945,30946,
92145 30947,30948,30949,30950,30951,30952,30953,30954,30955,30956,30957,30958,
92146 30959,30960,30961,30962,30963,30964,30965,30966,30967,30968,30969,30970,
92147 30971,30972,30973,30974,30975,30976,30977,30978,30979,30980,30981,30982,
92148 30983,30984,30985,30986,30987,30988,30989,30990,30991,30992,30993,30994,
92149 30995,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31006,
92150 31007,31008,31009,31010,31011,31012,31013,31014,31015,31016,31017,31018,
92151 31019,31020,31021,31022,31023,31024,31025,31026,31027,31028,31029,31030,
92152 31031,31032,31033,31034,31035,31036,31037,31038,31039,31040,31041,31042,
92153 31043,31044,31045,31046,31047,31048,31049,31050,31051,31052,31053,31054,
92154 31055,31056,31057,31058,31059,31060,31061,31062,31063,31064,31065,31066,
92155 31067,31068,31069,31070,31071,31072,31073,31074,31075,31076,31077,31078,
92156 31079,31080,31081,31082,31083,31084,31085,31086,31087,31088,31089,31090,
92157 31091,31092,31093,31094,31095,31096,31097,31098,31099,31100,31101,31102,
92158 31103,31104,31105,31106,31107,31108,31109,31110,31111,31112,31113,31114,
92159 31115,31116,31117,31118,31119,31120,31121,31122,31123,31124,31125,31126,
92160 31127,31128,31129,31130,31131,31132,31133,31134,31135,31136,31137,31138,
92161 31139,31140,31141,31142,31143,31144,31145,31146,31147,31148,31149,31150,
92162 31151,31152,31153,31154,31155,31156,31157,31158,31159,31160,31161,31162,
92163 31163,31164,31165,31166,31167,31168,31169,31170,31171,31172,31173,31174,
92164 31175,31176,31177,31178,31179,31180,31181,31182,31183,31184,31185,31186,
92165 31187,31188,31189,31190,31191,31192,31193,31194,31195,31196,31197,31198,
92166 31199,31200,31201,31202,31203,31204,31205,31206,31207,31208,31209,31210,
92167 31211,31212,31213,31214,31215,31216,31217,31218,31219,31220,31221,31222,
92168 31223,31224,31225,31226,31227,31228,31229,31230,31231,31232,31233,31234,
92169 31235,31236,31237,31238,31239,31240,31241,31242,31243,31244,31245,31246,
92170 31247,31248,31249,31250,31251,31252,31253,31254,31255,31256,31257,31258,
92171 31259,31260,31261,31262,31263,31264,31265,31266,31267,31268,31269,31270,
92172 31271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,
92173 31283,31284,31285,31286,31287,31288,31289,31290,31291,31292,31293,31294,
92174 31295,31296,31297,31298,31299,31300,31301,31302,31303,31304,31305,31306,
92175 31307,31308,31309,31310,31311,31312,31313,31314,31315,31316,31317,31318,
92176 31319,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330,
92177 31331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,
92178 31343,31344,31345,31346,31347,31348,31349,31350,31351,31352,31353,31354,
92179 31355,31356,31357,31358,31359,31360,31361,31362,31363,31364,31365,31366,
92180 31367,31368,31369,31370,31371,31372,31373,31374,31375,31376,31377,31378,
92181 31379,31380,31381,31382,31383,31384,31385,31386,31387,31388,31389,31390,
92182 31391,31392,31393,31394,31395,31396,31397,31398,31399,31400,31401,31402,
92183 31403,31404,31405,31406,31407,31408,31409,31410,31411,31412,31413,31414,
92184 31415,31416,31417,31418,31419,31420,31421,31422,31423,31424,31425,31426,
92185 31427,31428,31429,31430,31431,31432,31433,31434,31435,31436,31437,31438,
92186 31439,31440,31441,31442,31443,31444,31445,31446,31447,31448,31449,31450,
92187 31451,31452,31453,31454,31455,31456,31457,31458,31459,31460,31461,31462,
92188 31463,31464,31465,31466,31467,31468,31469,31470,31471,31472,31473,31474,
92189 31475,31476,31477,31478,31479,31480,31481,31482,31483,31484,31485,31486,
92190 31487,31488,31489,31490,31491,31492,31493,31494,31495,31496,31497,31498,
92191 31499,31500,31501,31502,31503,31504,31505,31506,31507,31508,31509,31510,
92192 31511,31512,31513,31514,31515,31516,31517,31518,31519,31520,31521,31522,
92193 31523,31524,31525,31526,31527,31528,31529,31530,31531,31532,31533,31534,
92194 31535,31536,31537,31538,31539,31540,31541,31542,31543,31544,31545,31546,
92195 31547,31548,31549,31550,31551,31552,31553,31554,31555,31556,31557,31558,
92196 31559,31560,31561,31562,31563,31564,31565,31566,31567,31568,31569,31570,
92197 31571,31572,31573,31574,31575,31576,31577,31578,31579,31580,31581,31582,
92198 31583,31584,31585,31586,31587,31588,31589,31590,31591,31592,31593,31594,
92199 31595,31596,31597,31598,31599,31600,31601,31602,31603,31604,31605,31606,
92200 31607,31608,31609,31610,31611,31612,31613,31614,31615,31616,31617,31618,
92201 31619,31620,31621,31622,31623,31624,31625,31626,31627,31628,31629,31630,
92202 31631,31632,31633,31634,31635,31636,31637,31638,31639,31640,31641,31642,
92203 31643,31644,31645,31646,31647,31648,31649,31650,31651,31652,31653,31654,
92204 31655,31656,31657,31658,31659,31660,31661,31662,31663,31664,31665,31666,
92205 31667,31668,31669,31670,31671,31672,31673,31674,31675,31676,31677,31678,
92206 31679,31680,31681,31682,31683,31684,31685,31686,31687,31688,31689,31690,
92207 31691,31692,31693,31694,31695,31696,31697,31698,31699,31700,31701,31702,
92208 31703,31704,31705,31706,31707,31708,31709,31710,31711,31712,31713,31714,
92209 31715,31716,31717,31718,31719,31720,31721,31722,31723,31724,31725,31726,
92210 31727,31728,31729,31730,31731,31732,31733,31734,31735,31736,31737,31738,
92211 31739,31740,31741,31742,31743,31744,31745,31746,31747,31748,31749,31750,
92212 31751,31752,31753,31754,31755,31756,31757,31758,31759,31760,31761,31762,
92213 31763,31764,31765,31766,31767,31768,31769,31770,31771,31772,31773,31774,
92214 31775,31776,31777,31778,31779,31780,31781,31782,31783,31784,31785,31786,
92215 31787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798,
92216 31799,31800,31801,31802,31803,31804,31805,31806,31807,31808,31809,31810,
92217 31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31821,31822,
92218 31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,
92219 31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,
92220 31847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,
92221 31859,31860,31861,31862,31863,31864,31865,31866,31867,31868,31869,31870,
92222 31871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31881,31882,
92223 31883,31884,31885,31886,31887,31888,31889,31890,31891,31892,31893,31894,
92224 31895,31896,31897,31898,31899,31900,31901,31902,31903,31904,31905,31906,
92225 31907,31908,31909,31910,31911,31912,31913,31914,31915,31916,31917,31918,
92226 31919,31920,31921,31922,31923,31924,31925,31926,31927,31928,31929,31930,
92227 31931,31932,31933,31934,31935,31936,31937,31938,31939,31940,31941,31942,
92228 31943,31944,31945,31946,31947,31948,31949,31950,31951,31952,31953,31954,
92229 31955,31956,31957,31958,31959,31960,31961,31962,31963,31964,31965,31966,
92230 31967,31968,31969,31970,31971,31972,31973,31974,31975,31976,31977,31978,
92231 31979,31980,31981,31982,31983,31984,31985,31986,31987,31988,31989,31990,
92232 31991,31992,31993,31994,31995,31996,31997,31998,31999,32000,32001,32002,
92233 32003,32004,32005,32006,32007,32008,32009,32010,32011,32012,32013,32014,
92234 32015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026,
92235 32027,32028,32029,32030,32031,32032,32033,32034,32035,32036,32037,32038,
92236 32039,32040,32041,32042,32043,32044,32045,32046,32047,32048,32049,32050,
92237 32051,32052,32053,32054,32055,32056,32057,32058,32059,32060,32061,32062,
92238 32063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074,
92239 32075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086,
92240 32087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098,
92241 32099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32110,
92242 32111,32112,32113,32114,32115,32116,32117,32118,32119,32120,32121,32122,
92243 32123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134,
92244 32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146,
92245 32147,32148,32149,32150,32151,32152,32153,32154,32155,32156,32157,32158,
92246 32159,32160,32161,32162,32163,32164,32165,32166,32167,32168,32169,32170,
92247 32171,32172,32173,32174,32175,32176,32177,32178,32179,32180,32181,32182,
92248 32183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194,
92249 32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,
92250 32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,
92251 32219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230,
92252 32231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242,
92253 32243,32244,32245,32246,32247,32248,32249,32250,32251,32252,32253,32254,
92254 32255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266,
92255 32267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278,
92256 32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290,
92257 32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302,
92258 32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314,
92259 32315,32316,32317,32318,32319,32320,32321,32322,32323,32324,32325,32326,
92260 32327,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338,
92261 32339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,32350,
92262 32351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362,
92263 32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374,
92264 32375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32386,
92265 32387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,
92266 32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410,
92267 32411,32412,32413,32414,32415,32416,32417,32418,32419,32420,32421,32422,
92268 32423,32424,32425,32426,32427,32428,32429,32430,32431,32432,32433,32434,
92269 32435,32436,32437,32438,32439,32440,32441,32442,32443,32444,32445,32446,
92270 32447,32448,32449,32450,32451,32452,32453,32454,32455,32456,32457,32458,
92271 32459,32460,32461,32462,32463,32464,32465,32466,32467,32468,32469,32470,
92272 32471,32472,32473,32474,32475,32476,32477,32478,32479,32480,32481,32482,
92273 32483,32484,32485,32486,32487,32488,32489,32490,32491,32492,32493,32494,
92274 32495,32496,32497,32498,32499,32500,32501,32502,32503,32504,32505,32506,
92275 32507,32508,32509,32510,32511,32512,32513,32514,32515,32516,32517,32518,
92276 32519,32520,32521,32522,32523,32524,32525,32526,32527,32528,32529,32530,
92277 32531,32532,32533,32534,32535,32536,32537,32538,32539,32540,32541,32542,
92278 32543,32544,32545,32546,32547,32548,32549,32550,32551,32552,32553,32554,
92279 32555,32556,32557,32558,32559,32560,32561,32562,32563,32564,32565,32566,
92280 32567,32568,32569,32570,32571,32572,32573,32574,32575,32576,32577,32578,
92281 32579,32580,32581,32582,32583,32584,32585,32586,32587,32588,32589,32590,
92282 32591,32592,32593,32594,32595,32596,32597,32598,32599,32600,32601,32602,
92283 32603,32604,32605,32606,32607,32608,32609,32610,32611,32612,32613,32614,
92284 32615,32616,32617,32618,32619,32620,32621,32622,32623,32624,32625,32626,
92285 32627,32628,32629,32630,32631,32632,32633,32634,32635,32636,32637,32638,
92286 32639,32640,32641,32642,32643,32644,32645,32646,32647,32648,32649,32650,
92287 32651,32652,32653,32654,32655,32656,32657,32658,32659,32660,32661,32662,
92288 32663,32664,32665,32666,32667,32668,32669,32670,32671,32672,32673,32674,
92289 32675,32676,32677,32678,32679,32680,32681,32682,32683,32684,32685,32686,
92290 32687,32688,32689,32690,32691,32692,32693,32694,32695,32696,32697,32698,
92291 32699,32700,32701,32702,32703,32704,32705,32706,32707,32708,32709,32710,
92292 32711,32712,32713,32714,32715,32716,32717,32718,32719,32720,32721,32722,
92293 32723,32724,32725,32726,32727,32728,32729,32730,32731,32732,32733,32734,
92294 32735,32736,32737,32738,32739,32740,32741,32742,32743,32744,32745,32746,
92295 32747,32748,32749,32750,32751,32752,32753,32754,32755,32756,32757,32758,
92296 32759,32760,32761,32762,32763,32764,32765,32766,32767,32768L,32769L,32770L,
92297 32771L,32772L,32773L,32774L,32775L,32776L,32777L,32778L,32779L,32780L,
92298 32781L,32782L,32783L,32784L,32785L,32786L,32787L,32788L,32789L,32790L,
92299 32791L,32792L,32793L,32794L,32795L,32796L,32797L,32798L,32799L,32800L,
92300 32801L,32802L,32803L,32804L,32805L,32806L,32807L,32808L,32809L,32810L,
92301 32811L,32812L,32813L,32814L,32815L,32816L,32817L,32818L,32819L,32820L,
92302 32821L,32822L,32823L,32824L,32825L,32826L,32827L,32828L,32829L,32830L,
92303 32831L,32832L,32833L,32834L,32835L,32836L,32837L,32838L,32839L,32840L,
92304 32841L,32842L,32843L,32844L,32845L,32846L,32847L,32848L,32849L,32850L,
92305 32851L,32852L,32853L,32854L,32855L,32856L,32857L,32858L,32859L,32860L,
92306 32861L,32862L,32863L,32864L,32865L,32866L,32867L,32868L,32869L,32870L,
92307 32871L,32872L,32873L,32874L,32875L,32876L,32877L,32878L,32879L,32880L,
92308 32881L,32882L,32883L,32884L,32885L,32886L,32887L,32888L,32889L,32890L,
92309 32891L,32892L,32893L,32894L,32895L,32896L,32897L,32898L,32899L,32900L,
92310 32901L,32902L,32903L,32904L,32905L,32906L,32907L,32908L,32909L,32910L,
92311 32911L,32912L,32913L,32914L,32915L,32916L,32917L,32918L,32919L,32920L,
92312 32921L,32922L,32923L,32924L,32925L,32926L,32927L,32928L,32929L,32930L,
92313 32931L,32932L,32933L,32934L,32935L,32936L,32937L,32938L,32939L,32940L,
92314 32941L,32942L,32943L,32944L,32945L,32946L,32947L,32948L,32949L,32950L,
92315 32951L,32952L,32953L,32954L,32955L,32956L,32957L,32958L,32959L,32960L,
92316 32961L,32962L,32963L,32964L,32965L,32966L,32967L,32968L,32969L,32970L,
92317 32971L,32972L,32973L,32974L,32975L,32976L,32977L,32978L,32979L,32980L,
92318 32981L,32982L,32983L,32984L,32985L,32986L,32987L,32988L,32989L,32990L,
92319 32991L,32992L,32993L,32994L,32995L,32996L,32997L,32998L,32999L,33000L,
92320 33001L,33002L,33003L,33004L,33005L,33006L,33007L,33008L,33009L,33010L,
92321 33011L,33012L,33013L,33014L,33015L,33016L,33017L,33018L,33019L,33020L,
92322 33021L,33022L,33023L,33024L,33025L,33026L,33027L,33028L,33029L,33030L,
92323 33031L,33032L,33033L,33034L,33035L,33036L,33037L,33038L,33039L,33040L,
92324 33041L,33042L,33043L,33044L,33045L,33046L,33047L,33048L,33049L,33050L,
92325 33051L,33052L,33053L,33054L,33055L,33056L,33057L,33058L,33059L,33060L,
92326 33061L,33062L,33063L,33064L,33065L,33066L,33067L,33068L,33069L,33070L,
92327 33071L,33072L,33073L,33074L,33075L,33076L,33077L,33078L,33079L,33080L,
92328 33081L,33082L,33083L,33084L,33085L,33086L,33087L,33088L,33089L,33090L,
92329 33091L,33092L,33093L,33094L,33095L,33096L,33097L,33098L,33099L,33100L,
92330 33101L,33102L,33103L,33104L,33105L,33106L,33107L,33108L,33109L,33110L,
92331 33111L,33112L,33113L,33114L,33115L,33116L,33117L,33118L,33119L,33120L,
92332 33121L,33122L,33123L,33124L,33125L,33126L,33127L,33128L,33129L,33130L,
92333 33131L,33132L,33133L,33134L,33135L,33136L,33137L,33138L,33139L,33140L,
92334 33141L,33142L,33143L,33144L,33145L,33146L,33147L,33148L,33149L,33150L,
92335 33151L,33152L,33153L,33154L,33155L,33156L,33157L,33158L,33159L,33160L,
92336 33161L,33162L,33163L,33164L,33165L,33166L,33167L,33168L,33169L,33170L,
92337 33171L,33172L,33173L,33174L,33175L,33176L,33177L,33178L,33179L,33180L,
92338 33181L,33182L,33183L,33184L,33185L,33186L,33187L,33188L,33189L,33190L,
92339 33191L,33192L,33193L,33194L,33195L,33196L,33197L,33198L,33199L,33200L,
92340 33201L,33202L,33203L,33204L,33205L,33206L,33207L,33208L,33209L,33210L,
92341 33211L,33212L,33213L,33214L,33215L,33216L,33217L,33218L,33219L,33220L,
92342 33221L,33222L,33223L,33224L,33225L,33226L,33227L,33228L,33229L,33230L,
92343 33231L,33232L,33233L,33234L,33235L,33236L,33237L,33238L,33239L,33240L,
92344 33241L,33242L,33243L,33244L,33245L,33246L,33247L,33248L,33249L,33250L,
92345 33251L,33252L,33253L,33254L,33255L,33256L,33257L,33258L,33259L,33260L,
92346 33261L,33262L,33263L,33264L,33265L,33266L,33267L,33268L,33269L,33270L,
92347 33271L,33272L,33273L,33274L,33275L,33276L,33277L,33278L,33279L,33280L,
92348 33281L,33282L,33283L,33284L,33285L,33286L,33287L,33288L,33289L,33290L,
92349 33291L,33292L,33293L,33294L,33295L,33296L,33297L,33298L,33299L,33300L,
92350 33301L,33302L,33303L,33304L,33305L,33306L,33307L,33308L,33309L,33310L,
92351 33311L,33312L,33313L,33314L,33315L,33316L,33317L,33318L,33319L,33320L,
92352 33321L,33322L,33323L,33324L,33325L,33326L,33327L,33328L,33329L,33330L,
92353 33331L,33332L,33333L,33334L,33335L,33336L,33337L,33338L,33339L,33340L,
92354 33341L,33342L,33343L,33344L,33345L,33346L,33347L,33348L,33349L,33350L,
92355 33351L,33352L,33353L,33354L,33355L,33356L,33357L,33358L,33359L,33360L,
92356 33361L,33362L,33363L,33364L,33365L,33366L,33367L,33368L,33369L,33370L,
92357 33371L,33372L,33373L,33374L,33375L,33376L,33377L,33378L,33379L,33380L,
92358 33381L,33382L,33383L,33384L,33385L,33386L,33387L,33388L,33389L,33390L,
92359 33391L,33392L,33393L,33394L,33395L,33396L,33397L,33398L,33399L,33400L,
92360 33401L,33402L,33403L,33404L,33405L,33406L,33407L,33408L,33409L,33410L,
92361 33411L,33412L,33413L,33414L,33415L,33416L,33417L,33418L,33419L,33420L,
92362 33421L,33422L,33423L,33424L,33425L,33426L,33427L,33428L,33429L,33430L,
92363 33431L,33432L,33433L,33434L,33435L,33436L,33437L,33438L,33439L,33440L,
92364 33441L,33442L,33443L,33444L,33445L,33446L,33447L,33448L,33449L,33450L,
92365 33451L,33452L,33453L,33454L,33455L,33456L,33457L,33458L,33459L,33460L,
92366 33461L,33462L,33463L,33464L,33465L,33466L,33467L,33468L,33469L,33470L,
92367 33471L,33472L,33473L,33474L,33475L,33476L,33477L,33478L,33479L,33480L,
92368 33481L,33482L,33483L,33484L,33485L,33486L,33487L,33488L,33489L,33490L,
92369 33491L,33492L,33493L,33494L,33495L,33496L,33497L,33498L,33499L,33500L,
92370 33501L,33502L,33503L,33504L,33505L,33506L,33507L,33508L,33509L,33510L,
92371 33511L,33512L,33513L,33514L,33515L,33516L,33517L,33518L,33519L,33520L,
92372 33521L,33522L,33523L,33524L,33525L,33526L,33527L,33528L,33529L,33530L,
92373 33531L,33532L,33533L,33534L,33535L,33536L,33537L,33538L,33539L,33540L,
92374 33541L,33542L,33543L,33544L,33545L,33546L,33547L,33548L,33549L,33550L,
92375 33551L,33552L,33553L,33554L,33555L,33556L,33557L,33558L,33559L,33560L,
92376 33561L,33562L,33563L,33564L,33565L,33566L,33567L,33568L,33569L,33570L,
92377 33571L,33572L,33573L,33574L,33575L,33576L,33577L,33578L,33579L,33580L,
92378 33581L,33582L,33583L,33584L,33585L,33586L,33587L,33588L,33589L,33590L,
92379 33591L,33592L,33593L,33594L,33595L,33596L,33597L,33598L,33599L,33600L,
92380 33601L,33602L,33603L,33604L,33605L,33606L,33607L,33608L,33609L,33610L,
92381 33611L,33612L,33613L,33614L,33615L,33616L,33617L,33618L,33619L,33620L,
92382 33621L,33622L,33623L,33624L,33625L,33626L,33627L,33628L,33629L,33630L,
92383 33631L,33632L,33633L,33634L,33635L,33636L,33637L,33638L,33639L,33640L,
92384 33641L,33642L,33643L,33644L,33645L,33646L,33647L,33648L,33649L,33650L,
92385 33651L,33652L,33653L,33654L,33655L,33656L,33657L,33658L,33659L,33660L,
92386 33661L,33662L,33663L,33664L,33665L,33666L,33667L,33668L,33669L,33670L,
92387 33671L,33672L,33673L,33674L,33675L,33676L,33677L,33678L,33679L,33680L,
92388 33681L,33682L,33683L,33684L,33685L,33686L,33687L,33688L,33689L,33690L,
92389 33691L,33692L,33693L,33694L,33695L,33696L,33697L,33698L,33699L,33700L,
92390 33701L,33702L,33703L,33704L,33705L,33706L,33707L,33708L,33709L,33710L,
92391 33711L,33712L,33713L,33714L,33715L,33716L,33717L,33718L,33719L,33720L,
92392 33721L,33722L,33723L,33724L,33725L,33726L,33727L,33728L,33729L,33730L,
92393 33731L,33732L,33733L,33734L,33735L,33736L,33737L,33738L,33739L,33740L,
92394 33741L,33742L,33743L,33744L,33745L,33746L,33747L,33748L,33749L,33750L,
92395 33751L,33752L,33753L,33754L,33755L,33756L,33757L,33758L,33759L,33760L,
92396 33761L,33762L,33763L,33764L,33765L,33766L,33767L,33768L,33769L,33770L,
92397 33771L,33772L,33773L,33774L,33775L,33776L,33777L,33778L,33779L,33780L,
92398 33781L,33782L,33783L,33784L,33785L,33786L,33787L,33788L,33789L,33790L,
92399 33791L,33792L,33793L,33794L,33795L,33796L,33797L,33798L,33799L,33800L,
92400 33801L,33802L,33803L,33804L,33805L,33806L,33807L,33808L,33809L,33810L,
92401 33811L,33812L,33813L,33814L,33815L,33816L,33817L,33818L,33819L,33820L,
92402 33821L,33822L,33823L,33824L,33825L,33826L,33827L,33828L,33829L,33830L,
92403 33831L,33832L,33833L,33834L,33835L,33836L,33837L,33838L,33839L,33840L,
92404 33841L,33842L,33843L,33844L,33845L,33846L,33847L,33848L,33849L,33850L,
92405 33851L,33852L,33853L,33854L,33855L,33856L,33857L,33858L,33859L,33860L,
92406 33861L,33862L,33863L,33864L,33865L,33866L,33867L,33868L,33869L,33870L,
92407 33871L,33872L,33873L,33874L,33875L,33876L,33877L,33878L,33879L,33880L,
92408 33881L,33882L,33883L,33884L,33885L,33886L,33887L,33888L,33889L,33890L,
92409 33891L,33892L,33893L,33894L,33895L,33896L,33897L,33898L,33899L,33900L,
92410 33901L,33902L,33903L,33904L,33905L,33906L,33907L,33908L,33909L,33910L,
92411 33911L,33912L,33913L,33914L,33915L,33916L,33917L,33918L,33919L,33920L,
92412 33921L,33922L,33923L,33924L,33925L,33926L,33927L,33928L,33929L,33930L,
92413 33931L,33932L,33933L,33934L,33935L,33936L,33937L,33938L,33939L,33940L,
92414 33941L,33942L,33943L,33944L,33945L,33946L,33947L,33948L,33949L,33950L,
92415 33951L,33952L,33953L,33954L,33955L,33956L,33957L,33958L,33959L,33960L,
92416 33961L,33962L,33963L,33964L,33965L,33966L,33967L,33968L,33969L,33970L,
92417 33971L,33972L,33973L,33974L,33975L,33976L,33977L,33978L,33979L,33980L,
92418 33981L,33982L,33983L,33984L,33985L,33986L,33987L,33988L,33989L,33990L,
92419 33991L,33992L,33993L,33994L,33995L,33996L,33997L,33998L,33999L,34000L,
92420 34001L,34002L,34003L,34004L,34005L,34006L,34007L,34008L,34009L,34010L,
92421 34011L,34012L,34013L,34014L,34015L,34016L,34017L,34018L,34019L,34020L,
92422 34021L,34022L,34023L,34024L,34025L,34026L,34027L,34028L,34029L,34030L,
92423 34031L,34032L,34033L,34034L,34035L,34036L,34037L,34038L,34039L,34040L,
92424 34041L,34042L,34043L,34044L,34045L,34046L,34047L,34048L,34049L,34050L,
92425 34051L,34052L,34053L,34054L,34055L,34056L,34057L,34058L,34059L,34060L,
92426 34061L,34062L,34063L,34064L,34065L,34066L,34067L,34068L,34069L,34070L,
92427 34071L,34072L,34073L,34074L,34075L,34076L,34077L,34078L,34079L,34080L,
92428 34081L,34082L,34083L,34084L,34085L,34086L,34087L,34088L,34089L,34090L,
92429 34091L,34092L,34093L,34094L,34095L,34096L,34097L,34098L,34099L,34100L,
92430 34101L,34102L,34103L,34104L,34105L,34106L,34107L,34108L,34109L,34110L,
92431 34111L,34112L,34113L,34114L,34115L,34116L,34117L,34118L,34119L,34120L,
92432 34121L,34122L,34123L,34124L,34125L,34126L,34127L,34128L,34129L,34130L,
92433 34131L,34132L,34133L,34134L,34135L,34136L,34137L,34138L,34139L,34140L,
92434 34141L,34142L,34143L,34144L,34145L,34146L,34147L,34148L,34149L,34150L,
92435 34151L,34152L,34153L,34154L,34155L,34156L,34157L,34158L,34159L,34160L,
92436 34161L,34162L,34163L,34164L,34165L,34166L,34167L,34168L,34169L,34170L,
92437 34171L,34172L,34173L,34174L,34175L,34176L,34177L,34178L,34179L,34180L,
92438 34181L,34182L,34183L,34184L,34185L,34186L,34187L,34188L,34189L,34190L,
92439 34191L,34192L,34193L,34194L,34195L,34196L,34197L,34198L,34199L,34200L,
92440 34201L,34202L,34203L,34204L,34205L,34206L,34207L,34208L,34209L,34210L,
92441 34211L,34212L,34213L,34214L,34215L,34216L,34217L,34218L,34219L,34220L,
92442 34221L,34222L,34223L,34224L,34225L,34226L,34227L,34228L,34229L,34230L,
92443 34231L,34232L,34233L,34234L,34235L,34236L,34237L,34238L,34239L,34240L,
92444 34241L,34242L,34243L,34244L,34245L,34246L,34247L,34248L,34249L,34250L,
92445 34251L,34252L,34253L,34254L,34255L,34256L,34257L,34258L,34259L,34260L,
92446 34261L,34262L,34263L,34264L,34265L,34266L,34267L,34268L,34269L,34270L,
92447 34271L,34272L,34273L,34274L,34275L,34276L,34277L,34278L,34279L,34280L,
92448 34281L,34282L,34283L,34284L,34285L,34286L,34287L,34288L,34289L,34290L,
92449 34291L,34292L,34293L,34294L,34295L,34296L,34297L,34298L,34299L,34300L,
92450 34301L,34302L,34303L,34304L,34305L,34306L,34307L,34308L,34309L,34310L,
92451 34311L,34312L,34313L,34314L,34315L,34316L,34317L,34318L,34319L,34320L,
92452 34321L,34322L,34323L,34324L,34325L,34326L,34327L,34328L,34329L,34330L,
92453 34331L,34332L,34333L,34334L,34335L,34336L,34337L,34338L,34339L,34340L,
92454 34341L,34342L,34343L,34344L,34345L,34346L,34347L,34348L,34349L,34350L,
92455 34351L,34352L,34353L,34354L,34355L,34356L,34357L,34358L,34359L,34360L,
92456 34361L,34362L,34363L,34364L,34365L,34366L,34367L,34368L,34369L,34370L,
92457 34371L,34372L,34373L,34374L,34375L,34376L,34377L,34378L,34379L,34380L,
92458 34381L,34382L,34383L,34384L,34385L,34386L,34387L,34388L,34389L,34390L,
92459 34391L,34392L,34393L,34394L,34395L,34396L,34397L,34398L,34399L,34400L,
92460 34401L,34402L,34403L,34404L,34405L,34406L,34407L,34408L,34409L,34410L,
92461 34411L,34412L,34413L,34414L,34415L,34416L,34417L,34418L,34419L,34420L,
92462 34421L,34422L,34423L,34424L,34425L,34426L,34427L,34428L,34429L,34430L,
92463 34431L,34432L,34433L,34434L,34435L,34436L,34437L,34438L,34439L,34440L,
92464 34441L,34442L,34443L,34444L,34445L,34446L,34447L,34448L,34449L,34450L,
92465 34451L,34452L,34453L,34454L,34455L,34456L,34457L,34458L,34459L,34460L,
92466 34461L,34462L,34463L,34464L,34465L,34466L,34467L,34468L,34469L,34470L,
92467 34471L,34472L,34473L,34474L,34475L,34476L,34477L,34478L,34479L,34480L,
92468 34481L,34482L,34483L,34484L,34485L,34486L,34487L,34488L,34489L,34490L,
92469 34491L,34492L,34493L,34494L,34495L,34496L,34497L,34498L,34499L,34500L,
92470 34501L,34502L,34503L,34504L,34505L,34506L,34507L,34508L,34509L,34510L,
92471 34511L,34512L,34513L,34514L,34515L,34516L,34517L,34518L,34519L,34520L,
92472 34521L,34522L,34523L,34524L,34525L,34526L,34527L,34528L,34529L,34530L,
92473 34531L,34532L,34533L,34534L,34535L,34536L,34537L,34538L,34539L,34540L,
92474 34541L,34542L,34543L,34544L,34545L,34546L,34547L,34548L,34549L,34550L,
92475 34551L,34552L,34553L,34554L,34555L,34556L,34557L,34558L,34559L,34560L,
92476 34561L,34562L,34563L,34564L,34565L,34566L,34567L,34568L,34569L,34570L,
92477 34571L,34572L,34573L,34574L,34575L,34576L,34577L,34578L,34579L,34580L,
92478 34581L,34582L,34583L,34584L,34585L,34586L,34587L,34588L,34589L,34590L,
92479 34591L,34592L,34593L,34594L,34595L,34596L,34597L,34598L,34599L,34600L,
92480 34601L,34602L,34603L,34604L,34605L,34606L,34607L,34608L,34609L,34610L,
92481 34611L,34612L,34613L,34614L,34615L,34616L,34617L,34618L,34619L,34620L,
92482 34621L,34622L,34623L,34624L,34625L,34626L,34627L,34628L,34629L,34630L,
92483 34631L,34632L,34633L,34634L,34635L,34636L,34637L,34638L,34639L,34640L,
92484 34641L,34642L,34643L,34644L,34645L,34646L,34647L,34648L,34649L,34650L,
92485 34651L,34652L,34653L,34654L,34655L,34656L,34657L,34658L,34659L,34660L,
92486 34661L,34662L,34663L,34664L,34665L,34666L,34667L,34668L,34669L,34670L,
92487 34671L,34672L,34673L,34674L,34675L,34676L,34677L,34678L,34679L,34680L,
92488 34681L,34682L,34683L,34684L,34685L,34686L,34687L,34688L,34689L,34690L,
92489 34691L,34692L,34693L,34694L,34695L,34696L,34697L,34698L,34699L,34700L,
92490 34701L,34702L,34703L,34704L,34705L,34706L,34707L,34708L,34709L,34710L,
92491 34711L,34712L,34713L,34714L,34715L,34716L,34717L,34718L,34719L,34720L,
92492 34721L,34722L,34723L,34724L,34725L,34726L,34727L,34728L,34729L,34730L,
92493 34731L,34732L,34733L,34734L,34735L,34736L,34737L,34738L,34739L,34740L,
92494 34741L,34742L,34743L,34744L,34745L,34746L,34747L,34748L,34749L,34750L,
92495 34751L,34752L,34753L,34754L,34755L,34756L,34757L,34758L,34759L,34760L,
92496 34761L,34762L,34763L,34764L,34765L,34766L,34767L,34768L,34769L,34770L,
92497 34771L,34772L,34773L,34774L,34775L,34776L,34777L,34778L,34779L,34780L,
92498 34781L,34782L,34783L,34784L,34785L,34786L,34787L,34788L,34789L,34790L,
92499 34791L,34792L,34793L,34794L,34795L,34796L,34797L,34798L,34799L,34800L,
92500 34801L,34802L,34803L,34804L,34805L,34806L,34807L,34808L,34809L,34810L,
92501 34811L,34812L,34813L,34814L,34815L,34816L,34817L,34818L,34819L,34820L,
92502 34821L,34822L,34823L,34824L,34825L,34826L,34827L,34828L,34829L,34830L,
92503 34831L,34832L,34833L,34834L,34835L,34836L,34837L,34838L,34839L,34840L,
92504 34841L,34842L,34843L,34844L,34845L,34846L,34847L,34848L,34849L,34850L,
92505 34851L,34852L,34853L,34854L,34855L,34856L,34857L,34858L,34859L,34860L,
92506 34861L,34862L,34863L,34864L,34865L,34866L,34867L,34868L,34869L,34870L,
92507 34871L,34872L,34873L,34874L,34875L,34876L,34877L,34878L,34879L,34880L,
92508 34881L,34882L,34883L,34884L,34885L,34886L,34887L,34888L,34889L,34890L,
92509 34891L,34892L,34893L,34894L,34895L,34896L,34897L,34898L,34899L,34900L,
92510 34901L,34902L,34903L,34904L,34905L,34906L,34907L,34908L,34909L,34910L,
92511 34911L,34912L,34913L,34914L,34915L,34916L,34917L,34918L,34919L,34920L,
92512 34921L,34922L,34923L,34924L,34925L,34926L,34927L,34928L,34929L,34930L,
92513 34931L,34932L,34933L,34934L,34935L,34936L,34937L,34938L,34939L,34940L,
92514 34941L,34942L,34943L,34944L,34945L,34946L,34947L,34948L,34949L,34950L,
92515 34951L,34952L,34953L,34954L,34955L,34956L,34957L,34958L,34959L,34960L,
92516 34961L,34962L,34963L,34964L,34965L,34966L,34967L,34968L,34969L,34970L,
92517 34971L,34972L,34973L,34974L,34975L,34976L,34977L,34978L,34979L,34980L,
92518 34981L,34982L,34983L,34984L,34985L,34986L,34987L,34988L,34989L,34990L,
92519 34991L,34992L,34993L,34994L,34995L,34996L,34997L,34998L,34999L,35000L,
92520 35001L,35002L,35003L,35004L,35005L,35006L,35007L,35008L,35009L,35010L,
92521 35011L,35012L,35013L,35014L,35015L,35016L,35017L,35018L,35019L,35020L,
92522 35021L,35022L,35023L,35024L,35025L,35026L,35027L,35028L,35029L,35030L,
92523 35031L,35032L,35033L,35034L,35035L,35036L,35037L,35038L,35039L,35040L,
92524 35041L,35042L,35043L,35044L,35045L,35046L,35047L,35048L,35049L,35050L,
92525 35051L,35052L,35053L,35054L,35055L,35056L,35057L,35058L,35059L,35060L,
92526 35061L,35062L,35063L,35064L,35065L,35066L,35067L,35068L,35069L,35070L,
92527 35071L,35072L,35073L,35074L,35075L,35076L,35077L,35078L,35079L,35080L,
92528 35081L,35082L,35083L,35084L,35085L,35086L,35087L,35088L,35089L,35090L,
92529 35091L,35092L,35093L,35094L,35095L,35096L,35097L,35098L,35099L,35100L,
92530 35101L,35102L,35103L,35104L,35105L,35106L,35107L,35108L,35109L,35110L,
92531 35111L,35112L,35113L,35114L,35115L,35116L,35117L,35118L,35119L,35120L,
92532 35121L,35122L,35123L,35124L,35125L,35126L,35127L,35128L,35129L,35130L,
92533 35131L,35132L,35133L,35134L,35135L,35136L,35137L,35138L,35139L,35140L,
92534 35141L,35142L,35143L,35144L,35145L,35146L,35147L,35148L,35149L,35150L,
92535 35151L,35152L,35153L,35154L,35155L,35156L,35157L,35158L,35159L,35160L,
92536 35161L,35162L,35163L,35164L,35165L,35166L,35167L,35168L,35169L,35170L,
92537 35171L,35172L,35173L,35174L,35175L,35176L,35177L,35178L,35179L,35180L,
92538 35181L,35182L,35183L,35184L,35185L,35186L,35187L,35188L,35189L,35190L,
92539 35191L,35192L,35193L,35194L,35195L,35196L,35197L,35198L,35199L,35200L,
92540 35201L,35202L,35203L,35204L,35205L,35206L,35207L,35208L,35209L,35210L,
92541 35211L,35212L,35213L,35214L,35215L,35216L,35217L,35218L,35219L,35220L,
92542 35221L,35222L,35223L,35224L,35225L,35226L,35227L,35228L,35229L,35230L,
92543 35231L,35232L,35233L,35234L,35235L,35236L,35237L,35238L,35239L,35240L,
92544 35241L,35242L,35243L,35244L,35245L,35246L,35247L,35248L,35249L,35250L,
92545 35251L,35252L,35253L,35254L,35255L,35256L,35257L,35258L,35259L,35260L,
92546 35261L,35262L,35263L,35264L,35265L,35266L,35267L,35268L,35269L,35270L,
92547 35271L,35272L,35273L,35274L,35275L,35276L,35277L,35278L,35279L,35280L,
92548 35281L,35282L,35283L,35284L,35285L,35286L,35287L,35288L,35289L,35290L,
92549 35291L,35292L,35293L,35294L,35295L,35296L,35297L,35298L,35299L,35300L,
92550 35301L,35302L,35303L,35304L,35305L,35306L,35307L,35308L,35309L,35310L,
92551 35311L,35312L,35313L,35314L,35315L,35316L,35317L,35318L,35319L,35320L,
92552 35321L,35322L,35323L,35324L,35325L,35326L,35327L,35328L,35329L,35330L,
92553 35331L,35332L,35333L,35334L,35335L,35336L,35337L,35338L,35339L,35340L,
92554 35341L,35342L,35343L,35344L,35345L,35346L,35347L,35348L,35349L,35350L,
92555 35351L,35352L,35353L,35354L,35355L,35356L,35357L,35358L,35359L,35360L,
92556 35361L,35362L,35363L,35364L,35365L,35366L,35367L,35368L,35369L,35370L,
92557 35371L,35372L,35373L,35374L,35375L,35376L,35377L,35378L,35379L,35380L,
92558 35381L,35382L,35383L,35384L,35385L,35386L,35387L,35388L,35389L,35390L,
92559 35391L,35392L,35393L,35394L,35395L,35396L,35397L,35398L,35399L,35400L,
92560 35401L,35402L,35403L,35404L,35405L,35406L,35407L,35408L,35409L,35410L,
92561 35411L,35412L,35413L,35414L,35415L,35416L,35417L,35418L,35419L,35420L,
92562 35421L,35422L,35423L,35424L,35425L,35426L,35427L,35428L,35429L,35430L,
92563 35431L,35432L,35433L,35434L,35435L,35436L,35437L,35438L,35439L,35440L,
92564 35441L,35442L,35443L,35444L,35445L,35446L,35447L,35448L,35449L,35450L,
92565 35451L,35452L,35453L,35454L,35455L,35456L,35457L,35458L,35459L,35460L,
92566 35461L,35462L,35463L,35464L,35465L,35466L,35467L,35468L,35469L,35470L,
92567 35471L,35472L,35473L,35474L,35475L,35476L,35477L,35478L,35479L,35480L,
92568 35481L,35482L,35483L,35484L,35485L,35486L,35487L,35488L,35489L,35490L,
92569 35491L,35492L,35493L,35494L,35495L,35496L,35497L,35498L,35499L,35500L,
92570 35501L,35502L,35503L,35504L,35505L,35506L,35507L,35508L,35509L,35510L,
92571 35511L,35512L,35513L,35514L,35515L,35516L,35517L,35518L,35519L,35520L,
92572 35521L,35522L,35523L,35524L,35525L,35526L,35527L,35528L,35529L,35530L,
92573 35531L,35532L,35533L,35534L,35535L,35536L,35537L,35538L,35539L,35540L,
92574 35541L,35542L,35543L,35544L,35545L,35546L,35547L,35548L,35549L,35550L,
92575 35551L,35552L,35553L,35554L,35555L,35556L,35557L,35558L,35559L,35560L,
92576 35561L,35562L,35563L,35564L,35565L,35566L,35567L,35568L,35569L,35570L,
92577 35571L,35572L,35573L,35574L,35575L,35576L,35577L,35578L,35579L,35580L,
92578 35581L,35582L,35583L,35584L,35585L,35586L,35587L,35588L,35589L,35590L,
92579 35591L,35592L,35593L,35594L,35595L,35596L,35597L,35598L,35599L,35600L,
92580 35601L,35602L,35603L,35604L,35605L,35606L,35607L,35608L,35609L,35610L,
92581 35611L,35612L,35613L,35614L,35615L,35616L,35617L,35618L,35619L,35620L,
92582 35621L,35622L,35623L,35624L,35625L,35626L,35627L,35628L,35629L,35630L,
92583 35631L,35632L,35633L,35634L,35635L,35636L,35637L,35638L,35639L,35640L,
92584 35641L,35642L,35643L,35644L,35645L,35646L,35647L,35648L,35649L,35650L,
92585 35651L,35652L,35653L,35654L,35655L,35656L,35657L,35658L,35659L,35660L,
92586 35661L,35662L,35663L,35664L,35665L,35666L,35667L,35668L,35669L,35670L,
92587 35671L,35672L,35673L,35674L,35675L,35676L,35677L,35678L,35679L,35680L,
92588 35681L,35682L,35683L,35684L,35685L,35686L,35687L,35688L,35689L,35690L,
92589 35691L,35692L,35693L,35694L,35695L,35696L,35697L,35698L,35699L,35700L,
92590 35701L,35702L,35703L,35704L,35705L,35706L,35707L,35708L,35709L,35710L,
92591 35711L,35712L,35713L,35714L,35715L,35716L,35717L,35718L,35719L,35720L,
92592 35721L,35722L,35723L,35724L,35725L,35726L,35727L,35728L,35729L,35730L,
92593 35731L,35732L,35733L,35734L,35735L,35736L,35737L,35738L,35739L,35740L,
92594 35741L,35742L,35743L,35744L,35745L,35746L,35747L,35748L,35749L,35750L,
92595 35751L,35752L,35753L,35754L,35755L,35756L,35757L,35758L,35759L,35760L,
92596 35761L,35762L,35763L,35764L,35765L,35766L,35767L,35768L,35769L,35770L,
92597 35771L,35772L,35773L,35774L,35775L,35776L,35777L,35778L,35779L,35780L,
92598 35781L,35782L,35783L,35784L,35785L,35786L,35787L,35788L,35789L,35790L,
92599 35791L,35792L,35793L,35794L,35795L,35796L,35797L,35798L,35799L,35800L,
92600 35801L,35802L,35803L,35804L,35805L,35806L,35807L,35808L,35809L,35810L,
92601 35811L,35812L,35813L,35814L,35815L,35816L,35817L,35818L,35819L,35820L,
92602 35821L,35822L,35823L,35824L,35825L,35826L,35827L,35828L,35829L,35830L,
92603 35831L,35832L,35833L,35834L,35835L,35836L,35837L,35838L,35839L,35840L,
92604 35841L,35842L,35843L,35844L,35845L,35846L,35847L,35848L,35849L,35850L,
92605 35851L,35852L,35853L,35854L,35855L,35856L,35857L,35858L,35859L,35860L,
92606 35861L,35862L,35863L,35864L,35865L,35866L,35867L,35868L,35869L,35870L,
92607 35871L,35872L,35873L,35874L,35875L,35876L,35877L,35878L,35879L,35880L,
92608 35881L,35882L,35883L,35884L,35885L,35886L,35887L,35888L,35889L,35890L,
92609 35891L,35892L,35893L,35894L,35895L,35896L,35897L,35898L,35899L,35900L,
92610 35901L,35902L,35903L,35904L,35905L,35906L,35907L,35908L,35909L,35910L,
92611 35911L,35912L,35913L,35914L,35915L,35916L,35917L,35918L,35919L,35920L,
92612 35921L,35922L,35923L,35924L,35925L,35926L,35927L,35928L,35929L,35930L,
92613 35931L,35932L,35933L,35934L,35935L,35936L,35937L,35938L,35939L,35940L,
92614 35941L,35942L,35943L,35944L,35945L,35946L,35947L,35948L,35949L,35950L,
92615 35951L,35952L,35953L,35954L,35955L,35956L,35957L,35958L,35959L,35960L,
92616 35961L,35962L,35963L,35964L,35965L,35966L,35967L,35968L,35969L,35970L,
92617 35971L,35972L,35973L,35974L,35975L,35976L,35977L,35978L,35979L,35980L,
92618 35981L,35982L,35983L,35984L,35985L,35986L,35987L,35988L,35989L,35990L,
92619 35991L,35992L,35993L,35994L,35995L,35996L,35997L,35998L,35999L,36000L,
92620 36001L,36002L,36003L,36004L,36005L,36006L,36007L,36008L,36009L,36010L,
92621 36011L,36012L,36013L,36014L,36015L,36016L,36017L,36018L,36019L,36020L,
92622 36021L,36022L,36023L,36024L,36025L,36026L,36027L,36028L,36029L,36030L,
92623 36031L,36032L,36033L,36034L,36035L,36036L,36037L,36038L,36039L,36040L,
92624 36041L,36042L,36043L,36044L,36045L,36046L,36047L,36048L,36049L,36050L,
92625 36051L,36052L,36053L,36054L,36055L,36056L,36057L,36058L,36059L,36060L,
92626 36061L,36062L,36063L,36064L,36065L,36066L,36067L,36068L,36069L,36070L,
92627 36071L,36072L,36073L,36074L,36075L,36076L,36077L,36078L,36079L,36080L,
92628 36081L,36082L,36083L,36084L,36085L,36086L,36087L,36088L,36089L,36090L,
92629 36091L,36092L,36093L,36094L,36095L,36096L,36097L,36098L,36099L,36100L,
92630 36101L,36102L,36103L,36104L,36105L,36106L,36107L,36108L,36109L,36110L,
92631 36111L,36112L,36113L,36114L,36115L,36116L,36117L,36118L,36119L,36120L,
92632 36121L,36122L,36123L,36124L,36125L,36126L,36127L,36128L,36129L,36130L,
92633 36131L,36132L,36133L,36134L,36135L,36136L,36137L,36138L,36139L,36140L,
92634 36141L,36142L,36143L,36144L,36145L,36146L,36147L,36148L,36149L,36150L,
92635 36151L,36152L,36153L,36154L,36155L,36156L,36157L,36158L,36159L,36160L,
92636 36161L,36162L,36163L,36164L,36165L,36166L,36167L,36168L,36169L,36170L,
92637 36171L,36172L,36173L,36174L,36175L,36176L,36177L,36178L,36179L,36180L,
92638 36181L,36182L,36183L,36184L,36185L,36186L,36187L,36188L,36189L,36190L,
92639 36191L,36192L,36193L,36194L,36195L,36196L,36197L,36198L,36199L,36200L,
92640 36201L,36202L,36203L,36204L,36205L,36206L,36207L,36208L,36209L,36210L,
92641 36211L,36212L,36213L,36214L,36215L,36216L,36217L,36218L,36219L,36220L,
92642 36221L,36222L,36223L,36224L,36225L,36226L,36227L,36228L,36229L,36230L,
92643 36231L,36232L,36233L,36234L,36235L,36236L,36237L,36238L,36239L,36240L,
92644 36241L,36242L,36243L,36244L,36245L,36246L,36247L,36248L,36249L,36250L,
92645 36251L,36252L,36253L,36254L,36255L,36256L,36257L,36258L,36259L,36260L,
92646 36261L,36262L,36263L,36264L,36265L,36266L,36267L,36268L,36269L,36270L,
92647 36271L,36272L,36273L,36274L,36275L,36276L,36277L,36278L,36279L,36280L,
92648 36281L,36282L,36283L,36284L,36285L,36286L,36287L,36288L,36289L,36290L,
92649 36291L,36292L,36293L,36294L,36295L,36296L,36297L,36298L,36299L,36300L,
92650 36301L,36302L,36303L,36304L,36305L,36306L,36307L,36308L,36309L,36310L,
92651 36311L,36312L,36313L,36314L,36315L,36316L,36317L,36318L,36319L,36320L,
92652 36321L,36322L,36323L,36324L,36325L,36326L,36327L,36328L,36329L,36330L,
92653 36331L,36332L,36333L,36334L,36335L,36336L,36337L,36338L,36339L,36340L,
92654 36341L,36342L,36343L,36344L,36345L,36346L,36347L,36348L,36349L,36350L,
92655 36351L,36352L,36353L,36354L,36355L,36356L,36357L,36358L,36359L,36360L,
92656 36361L,36362L,36363L,36364L,36365L,36366L,36367L,36368L,36369L,36370L,
92657 36371L,36372L,36373L,36374L,36375L,36376L,36377L,36378L,36379L,36380L,
92658 36381L,36382L,36383L,36384L,36385L,36386L,36387L,36388L,36389L,36390L,
92659 36391L,36392L,36393L,36394L,36395L,36396L,36397L,36398L,36399L,36400L,
92660 36401L,36402L,36403L,36404L,36405L,36406L,36407L,36408L,36409L,36410L,
92661 36411L,36412L,36413L,36414L,36415L,36416L,36417L,36418L,36419L,36420L,
92662 36421L,36422L,36423L,36424L,36425L,36426L,36427L,36428L,36429L,36430L,
92663 36431L,36432L,36433L,36434L,36435L,36436L,36437L,36438L,36439L,36440L,
92664 36441L,36442L,36443L,36444L,36445L,36446L,36447L,36448L,36449L,36450L,
92665 36451L,36452L,36453L,36454L,36455L,36456L,36457L,36458L,36459L,36460L,
92666 36461L,36462L,36463L,36464L,36465L,36466L,36467L,36468L,36469L,36470L,
92667 36471L,36472L,36473L,36474L,36475L,36476L,36477L,36478L,36479L,36480L,
92668 36481L,36482L,36483L,36484L,36485L,36486L,36487L,36488L,36489L,36490L,
92669 36491L,36492L,36493L,36494L,36495L,36496L,36497L,36498L,36499L,36500L,
92670 36501L,36502L,36503L,36504L,36505L,36506L,36507L,36508L,36509L,36510L,
92671 36511L,36512L,36513L,36514L,36515L,36516L,36517L,36518L,36519L,36520L,
92672 36521L,36522L,36523L,36524L,36525L,36526L,36527L,36528L,36529L,36530L,
92673 36531L,36532L,36533L,36534L,36535L,36536L,36537L,36538L,36539L,36540L,
92674 36541L,36542L,36543L,36544L,36545L,36546L,36547L,36548L,36549L,36550L,
92675 36551L,36552L,36553L,36554L,36555L,36556L,36557L,36558L,36559L,36560L,
92676 36561L,36562L,36563L,36564L,36565L,36566L,36567L,36568L,36569L,36570L,
92677 36571L,36572L,36573L,36574L,36575L,36576L,36577L,36578L,36579L,36580L,
92678 36581L,36582L,36583L,36584L,36585L,36586L,36587L,36588L,36589L,36590L,
92679 36591L,36592L,36593L,36594L,36595L,36596L,36597L,36598L,36599L,36600L,
92680 36601L,36602L,36603L,36604L,36605L,36606L,36607L,36608L,36609L,36610L,
92681 36611L,36612L,36613L,36614L,36615L,36616L,36617L,36618L,36619L,36620L,
92682 36621L,36622L,36623L,36624L,36625L,36626L,36627L,36628L,36629L,36630L,
92683 36631L,36632L,36633L,36634L,36635L,36636L,36637L,36638L,36639L,36640L,
92684 36641L,36642L,36643L,36644L,36645L,36646L,36647L,36648L,36649L,36650L,
92685 36651L,36652L,36653L,36654L,36655L,36656L,36657L,36658L,36659L,36660L,
92686 36661L,36662L,36663L,36664L,36665L,36666L,36667L,36668L,36669L,36670L,
92687 36671L,36672L,36673L,36674L,36675L,36676L,36677L,36678L,36679L,36680L,
92688 36681L,36682L,36683L,36684L,36685L,36686L,36687L,36688L,36689L,36690L,
92689 36691L,36692L,36693L,36694L,36695L,36696L,36697L,36698L,36699L,36700L,
92690 36701L,36702L,36703L,36704L,36705L,36706L,36707L,36708L,36709L,36710L,
92691 36711L,36712L,36713L,36714L,36715L,36716L,36717L,36718L,36719L,36720L,
92692 36721L,36722L,36723L,36724L,36725L,36726L,36727L,36728L,36729L,36730L,
92693 36731L,36732L,36733L,36734L,36735L,36736L,36737L,36738L,36739L,36740L,
92694 36741L,36742L,36743L,36744L,36745L,36746L,36747L,36748L,36749L,36750L,
92695 36751L,36752L,36753L,36754L,36755L,36756L,36757L,36758L,36759L,36760L,
92696 36761L,36762L,36763L,36764L,36765L,36766L,36767L,36768L,36769L,36770L,
92697 36771L,36772L,36773L,36774L,36775L,36776L,36777L,36778L,36779L,36780L,
92698 36781L,36782L,36783L,36784L,36785L,36786L,36787L,36788L,36789L,36790L,
92699 36791L,36792L,36793L,36794L,36795L,36796L,36797L,36798L,36799L,36800L,
92700 36801L,36802L,36803L,36804L,36805L,36806L,36807L,36808L,36809L,36810L,
92701 36811L,36812L,36813L,36814L,36815L,36816L,36817L,36818L,36819L,36820L,
92702 36821L,36822L,36823L,36824L,36825L,36826L,36827L,36828L,36829L,36830L,
92703 36831L,36832L,36833L,36834L,36835L,36836L,36837L,36838L,36839L,36840L,
92704 36841L,36842L,36843L,36844L,36845L,36846L,36847L,36848L,36849L,36850L,
92705 36851L,36852L,36853L,36854L,36855L,36856L,36857L,36858L,36859L,36860L,
92706 36861L,36862L,36863L,36864L,36865L,36866L,36867L,36868L,36869L,36870L,
92707 36871L,36872L,36873L,36874L,36875L,36876L,36877L,36878L,36879L,36880L,
92708 36881L,36882L,36883L,36884L,36885L,36886L,36887L,36888L,36889L,36890L,
92709 36891L,36892L,36893L,36894L,36895L,36896L,36897L,36898L,36899L,36900L,
92710 36901L,36902L,36903L,36904L,36905L,36906L,36907L,36908L,36909L,36910L,
92711 36911L,36912L,36913L,36914L,36915L,36916L,36917L,36918L,36919L,36920L,
92712 36921L,36922L,36923L,36924L,36925L,36926L,36927L,36928L,36929L,36930L,
92713 36931L,36932L,36933L,36934L,36935L,36936L,36937L,36938L,36939L,36940L,
92714 36941L,36942L,36943L,36944L,36945L,36946L,36947L,36948L,36949L,36950L,
92715 36951L,36952L,36953L,36954L,36955L,36956L,36957L,36958L,36959L,36960L,
92716 36961L,36962L,36963L,36964L,36965L,36966L,36967L,36968L,36969L,36970L,
92717 36971L,36972L,36973L,36974L,36975L,36976L,36977L,36978L,36979L,36980L,
92718 36981L,36982L,36983L,36984L,36985L,36986L,36987L,36988L,36989L,36990L,
92719 36991L,36992L,36993L,36994L,36995L,36996L,36997L,36998L,36999L,37000L,
92720 37001L,37002L,37003L,37004L,37005L,37006L,37007L,37008L,37009L,37010L,
92721 37011L,37012L,37013L,37014L,37015L,37016L,37017L,37018L,37019L,37020L,
92722 37021L,37022L,37023L,37024L,37025L,37026L,37027L,37028L,37029L,37030L,
92723 37031L,37032L,37033L,37034L,37035L,37036L,37037L,37038L,37039L,37040L,
92724 37041L,37042L,37043L,37044L,37045L,37046L,37047L,37048L,37049L,37050L,
92725 37051L,37052L,37053L,37054L,37055L,37056L,37057L,37058L,37059L,37060L,
92726 37061L,37062L,37063L,37064L,37065L,37066L,37067L,37068L,37069L,37070L,
92727 37071L,37072L,37073L,37074L,37075L,37076L,37077L,37078L,37079L,37080L,
92728 37081L,37082L,37083L,37084L,37085L,37086L,37087L,37088L,37089L,37090L,
92729 37091L,37092L,37093L,37094L,37095L,37096L,37097L,37098L,37099L,37100L,
92730 37101L,37102L,37103L,37104L,37105L,37106L,37107L,37108L,37109L,37110L,
92731 37111L,37112L,37113L,37114L,37115L,37116L,37117L,37118L,37119L,37120L,
92732 37121L,37122L,37123L,37124L,37125L,37126L,37127L,37128L,37129L,37130L,
92733 37131L,37132L,37133L,37134L,37135L,37136L,37137L,37138L,37139L,37140L,
92734 37141L,37142L,37143L,37144L,37145L,37146L,37147L,37148L,37149L,37150L,
92735 37151L,37152L,37153L,37154L,37155L,37156L,37157L,37158L,37159L,37160L,
92736 37161L,37162L,37163L,37164L,37165L,37166L,37167L,37168L,37169L,37170L,
92737 37171L,37172L,37173L,37174L,37175L,37176L,37177L,37178L,37179L,37180L,
92738 37181L,37182L,37183L,37184L,37185L,37186L,37187L,37188L,37189L,37190L,
92739 37191L,37192L,37193L,37194L,37195L,37196L,37197L,37198L,37199L,37200L,
92740 37201L,37202L,37203L,37204L,37205L,37206L,37207L,37208L,37209L,37210L,
92741 37211L,37212L,37213L,37214L,37215L,37216L,37217L,37218L,37219L,37220L,
92742 37221L,37222L,37223L,37224L,37225L,37226L,37227L,37228L,37229L,37230L,
92743 37231L,37232L,37233L,37234L,37235L,37236L,37237L,37238L,37239L,37240L,
92744 37241L,37242L,37243L,37244L,37245L,37246L,37247L,37248L,37249L,37250L,
92745 37251L,37252L,37253L,37254L,37255L,37256L,37257L,37258L,37259L,37260L,
92746 37261L,37262L,37263L,37264L,37265L,37266L,37267L,37268L,37269L,37270L,
92747 37271L,37272L,37273L,37274L,37275L,37276L,37277L,37278L,37279L,37280L,
92748 37281L,37282L,37283L,37284L,37285L,37286L,37287L,37288L,37289L,37290L,
92749 37291L,37292L,37293L,37294L,37295L,37296L,37297L,37298L,37299L,37300L,
92750 37301L,37302L,37303L,37304L,37305L,37306L,37307L,37308L,37309L,37310L,
92751 37311L,37312L,37313L,37314L,37315L,37316L,37317L,37318L,37319L,37320L,
92752 37321L,37322L,37323L,37324L,37325L,37326L,37327L,37328L,37329L,37330L,
92753 37331L,37332L,37333L,37334L,37335L,37336L,37337L,37338L,37339L,37340L,
92754 37341L,37342L,37343L,37344L,37345L,37346L,37347L,37348L,37349L,37350L,
92755 37351L,37352L,37353L,37354L,37355L,37356L,37357L,37358L,37359L,37360L,
92756 37361L,37362L,37363L,37364L,37365L,37366L,37367L,37368L,37369L,37370L,
92757 37371L,37372L,37373L,37374L,37375L,37376L,37377L,37378L,37379L,37380L,
92758 37381L,37382L,37383L,37384L,37385L,37386L,37387L,37388L,37389L,37390L,
92759 37391L,37392L,37393L,37394L,37395L,37396L,37397L,37398L,37399L,37400L,
92760 37401L,37402L,37403L,37404L,37405L,37406L,37407L,37408L,37409L,37410L,
92761 37411L,37412L,37413L,37414L,37415L,37416L,37417L,37418L,37419L,37420L,
92762 37421L,37422L,37423L,37424L,37425L,37426L,37427L,37428L,37429L,37430L,
92763 37431L,37432L,37433L,37434L,37435L,37436L,37437L,37438L,37439L,37440L,
92764 37441L,37442L,37443L,37444L,37445L,37446L,37447L,37448L,37449L,37450L,
92765 37451L,37452L,37453L,37454L,37455L,37456L,37457L,37458L,37459L,37460L,
92766 37461L,37462L,37463L,37464L,37465L,37466L,37467L,37468L,37469L,37470L,
92767 37471L,37472L,37473L,37474L,37475L,37476L,37477L,37478L,37479L,37480L,
92768 37481L,37482L,37483L,37484L,37485L,37486L,37487L,37488L,37489L,37490L,
92769 37491L,37492L,37493L,37494L,37495L,37496L,37497L,37498L,37499L,37500L,
92770 37501L,37502L,37503L,37504L,37505L,37506L,37507L,37508L,37509L,37510L,
92771 37511L,37512L,37513L,37514L,37515L,37516L,37517L,37518L,37519L,37520L,
92772 37521L,37522L,37523L,37524L,37525L,37526L,37527L,37528L,37529L,37530L,
92773 37531L,37532L,37533L,37534L,37535L,37536L,37537L,37538L,37539L,37540L,
92774 37541L,37542L,37543L,37544L,37545L,37546L,37547L,37548L,37549L,37550L,
92775 37551L,37552L,37553L,37554L,37555L,37556L,37557L,37558L,37559L,37560L,
92776 37561L,37562L,37563L,37564L,37565L,37566L,37567L,37568L,37569L,37570L,
92777 37571L,37572L,37573L,37574L,37575L,37576L,37577L,37578L,37579L,37580L,
92778 37581L,37582L,37583L,37584L,37585L,37586L,37587L,37588L,37589L,37590L,
92779 37591L,37592L,37593L,37594L,37595L,37596L,37597L,37598L,37599L,37600L,
92780 37601L,37602L,37603L,37604L,37605L,37606L,37607L,37608L,37609L,37610L,
92781 37611L,37612L,37613L,37614L,37615L,37616L,37617L,37618L,37619L,37620L,
92782 37621L,37622L,37623L,37624L,37625L,37626L,37627L,37628L,37629L,37630L,
92783 37631L,37632L,37633L,37634L,37635L,37636L,37637L,37638L,37639L,37640L,
92784 37641L,37642L,37643L,37644L,37645L,37646L,37647L,37648L,37649L,37650L,
92785 37651L,37652L,37653L,37654L,37655L,37656L,37657L,37658L,37659L,37660L,
92786 37661L,37662L,37663L,37664L,37665L,37666L,37667L,37668L,37669L,37670L,
92787 37671L,37672L,37673L,37674L,37675L,37676L,37677L,37678L,37679L,37680L,
92788 37681L,37682L,37683L,37684L,37685L,37686L,37687L,37688L,37689L,37690L,
92789 37691L,37692L,37693L,37694L,37695L,37696L,37697L,37698L,37699L,37700L,
92790 37701L,37702L,37703L,37704L,37705L,37706L,37707L,37708L,37709L,37710L,
92791 37711L,37712L,37713L,37714L,37715L,37716L,37717L,37718L,37719L,37720L,
92792 37721L,37722L,37723L,37724L,37725L,37726L,37727L,37728L,37729L,37730L,
92793 37731L,37732L,37733L,37734L,37735L,37736L,37737L,37738L,37739L,37740L,
92794 37741L,37742L,37743L,37744L,37745L,37746L,37747L,37748L,37749L,37750L,
92795 37751L,37752L,37753L,37754L,37755L,37756L,37757L,37758L,37759L,37760L,
92796 37761L,37762L,37763L,37764L,37765L,37766L,37767L,37768L,37769L,37770L,
92797 37771L,37772L,37773L,37774L,37775L,37776L,37777L,37778L,37779L,37780L,
92798 37781L,37782L,37783L,37784L,37785L,37786L,37787L,37788L,37789L,37790L,
92799 37791L,37792L,37793L,37794L,37795L,37796L,37797L,37798L,37799L,37800L,
92800 37801L,37802L,37803L,37804L,37805L,37806L,37807L,37808L,37809L,37810L,
92801 37811L,37812L,37813L,37814L,37815L,37816L,37817L,37818L,37819L,37820L,
92802 37821L,37822L,37823L,37824L,37825L,37826L,37827L,37828L,37829L,37830L,
92803 37831L,37832L,37833L,37834L,37835L,37836L,37837L,37838L,37839L,37840L,
92804 37841L,37842L,37843L,37844L,37845L,37846L,37847L,37848L,37849L,37850L,
92805 37851L,37852L,37853L,37854L,37855L,37856L,37857L,37858L,37859L,37860L,
92806 37861L,37862L,37863L,37864L,37865L,37866L,37867L,37868L,37869L,37870L,
92807 37871L,37872L,37873L,37874L,37875L,37876L,37877L,37878L,37879L,37880L,
92808 37881L,37882L,37883L,37884L,37885L,37886L,37887L,37888L,37889L,37890L,
92809 37891L,37892L,37893L,37894L,37895L,37896L,37897L,37898L,37899L,37900L,
92810 37901L,37902L,37903L,37904L,37905L,37906L,37907L,37908L,37909L,37910L,
92811 37911L,37912L,37913L,37914L,37915L,37916L,37917L,37918L,37919L,37920L,
92812 37921L,37922L,37923L,37924L,37925L,37926L,37927L,37928L,37929L,37930L,
92813 37931L,37932L,37933L,37934L,37935L,37936L,37937L,37938L,37939L,37940L,
92814 37941L,37942L,37943L,37944L,37945L,37946L,37947L,37948L,37949L,37950L,
92815 37951L,37952L,37953L,37954L,37955L,37956L,37957L,37958L,37959L,37960L,
92816 37961L,37962L,37963L,37964L,37965L,37966L,37967L,37968L,37969L,37970L,
92817 37971L,37972L,37973L,37974L,37975L,37976L,37977L,37978L,37979L,37980L,
92818 37981L,37982L,37983L,37984L,37985L,37986L,37987L,37988L,37989L,37990L,
92819 37991L,37992L,37993L,37994L,37995L,37996L,37997L,37998L,37999L,38000L,
92820 38001L,38002L,38003L,38004L,38005L,38006L,38007L,38008L,38009L,38010L,
92821 38011L,38012L,38013L,38014L,38015L,38016L,38017L,38018L,38019L,38020L,
92822 38021L,38022L,38023L,38024L,38025L,38026L,38027L,38028L,38029L,38030L,
92823 38031L,38032L,38033L,38034L,38035L,38036L,38037L,38038L,38039L,38040L,
92824 38041L,38042L,38043L,38044L,38045L,38046L,38047L,38048L,38049L,38050L,
92825 38051L,38052L,38053L,38054L,38055L,38056L,38057L,38058L,38059L,38060L,
92826 38061L,38062L,38063L,38064L,38065L,38066L,38067L,38068L,38069L,38070L,
92827 38071L,38072L,38073L,38074L,38075L,38076L,38077L,38078L,38079L,38080L,
92828 38081L,38082L,38083L,38084L,38085L,38086L,38087L,38088L,38089L,38090L,
92829 38091L,38092L,38093L,38094L,38095L,38096L,38097L,38098L,38099L,38100L,
92830 38101L,38102L,38103L,38104L,38105L,38106L,38107L,38108L,38109L,38110L,
92831 38111L,38112L,38113L,38114L,38115L,38116L,38117L,38118L,38119L,38120L,
92832 38121L,38122L,38123L,38124L,38125L,38126L,38127L,38128L,38129L,38130L,
92833 38131L,38132L,38133L,38134L,38135L,38136L,38137L,38138L,38139L,38140L,
92834 38141L,38142L,38143L,38144L,38145L,38146L,38147L,38148L,38149L,38150L,
92835 38151L,38152L,38153L,38154L,38155L,38156L,38157L,38158L,38159L,38160L,
92836 38161L,38162L,38163L,38164L,38165L,38166L,38167L,38168L,38169L,38170L,
92837 38171L,38172L,38173L,38174L,38175L,38176L,38177L,38178L,38179L,38180L,
92838 38181L,38182L,38183L,38184L,38185L,38186L,38187L,38188L,38189L,38190L,
92839 38191L,38192L,38193L,38194L,38195L,38196L,38197L,38198L,38199L,38200L,
92840 38201L,38202L,38203L,38204L,38205L,38206L,38207L,38208L,38209L,38210L,
92841 38211L,38212L,38213L,38214L,38215L,38216L,38217L,38218L,38219L,38220L,
92842 38221L,38222L,38223L,38224L,38225L,38226L,38227L,38228L,38229L,38230L,
92843 38231L,38232L,38233L,38234L,38235L,38236L,38237L,38238L,38239L,38240L,
92844 38241L,38242L,38243L,38244L,38245L,38246L,38247L,38248L,38249L,38250L,
92845 38251L,38252L,38253L,38254L,38255L,38256L,38257L,38258L,38259L,38260L,
92846 38261L,38262L,38263L,38264L,38265L,38266L,38267L,38268L,38269L,38270L,
92847 38271L,38272L,38273L,38274L,38275L,38276L,38277L,38278L,38279L,38280L,
92848 38281L,38282L,38283L,38284L,38285L,38286L,38287L,38288L,38289L,38290L,
92849 38291L,38292L,38293L,38294L,38295L,38296L,38297L,38298L,38299L,38300L,
92850 38301L,38302L,38303L,38304L,38305L,38306L,38307L,38308L,38309L,38310L,
92851 38311L,38312L,38313L,38314L,38315L,38316L,38317L,38318L,38319L,38320L,
92852 38321L,38322L,38323L,38324L,38325L,38326L,38327L,38328L,38329L,38330L,
92853 38331L,38332L,38333L,38334L,38335L,38336L,38337L,38338L,38339L,38340L,
92854 38341L,38342L,38343L,38344L,38345L,38346L,38347L,38348L,38349L,38350L,
92855 38351L,38352L,38353L,38354L,38355L,38356L,38357L,38358L,38359L,38360L,
92856 38361L,38362L,38363L,38364L,38365L,38366L,38367L,38368L,38369L,38370L,
92857 38371L,38372L,38373L,38374L,38375L,38376L,38377L,38378L,38379L,38380L,
92858 38381L,38382L,38383L,38384L,38385L,38386L,38387L,38388L,38389L,38390L,
92859 38391L,38392L,38393L,38394L,38395L,38396L,38397L,38398L,38399L,38400L,
92860 38401L,38402L,38403L,38404L,38405L,38406L,38407L,38408L,38409L,38410L,
92861 38411L,38412L,38413L,38414L,38415L,38416L,38417L,38418L,38419L,38420L,
92862 38421L,38422L,38423L,38424L,38425L,38426L,38427L,38428L,38429L,38430L,
92863 38431L,38432L,38433L,38434L,38435L,38436L,38437L,38438L,38439L,38440L,
92864 38441L,38442L,38443L,38444L,38445L,38446L,38447L,38448L,38449L,38450L,
92865 38451L,38452L,38453L,38454L,38455L,38456L,38457L,38458L,38459L,38460L,
92866 38461L,38462L,38463L,38464L,38465L,38466L,38467L,38468L,38469L,38470L,
92867 38471L,38472L,38473L,38474L,38475L,38476L,38477L,38478L,38479L,38480L,
92868 38481L,38482L,38483L,38484L,38485L,38486L,38487L,38488L,38489L,38490L,
92869 38491L,38492L,38493L,38494L,38495L,38496L,38497L,38498L,38499L,38500L,
92870 38501L,38502L,38503L,38504L,38505L,38506L,38507L,38508L,38509L,38510L,
92871 38511L,38512L,38513L,38514L,38515L,38516L,38517L,38518L,38519L,38520L,
92872 38521L,38522L,38523L,38524L,38525L,38526L,38527L,38528L,38529L,38530L,
92873 38531L,38532L,38533L,38534L,38535L,38536L,38537L,38538L,38539L,38540L,
92874 38541L,38542L,38543L,38544L,38545L,38546L,38547L,38548L,38549L,38550L,
92875 38551L,38552L,38553L,38554L,38555L,38556L,38557L,38558L,38559L,38560L,
92876 38561L,38562L,38563L,38564L,38565L,38566L,38567L,38568L,38569L,38570L,
92877 38571L,38572L,38573L,38574L,38575L,38576L,38577L,38578L,38579L,38580L,
92878 38581L,38582L,38583L,38584L,38585L,38586L,38587L,38588L,38589L,38590L,
92879 38591L,38592L,38593L,38594L,38595L,38596L,38597L,38598L,38599L,38600L,
92880 38601L,38602L,38603L,38604L,38605L,38606L,38607L,38608L,38609L,38610L,
92881 38611L,38612L,38613L,38614L,38615L,38616L,38617L,38618L,38619L,38620L,
92882 38621L,38622L,38623L,38624L,38625L,38626L,38627L,38628L,38629L,38630L,
92883 38631L,38632L,38633L,38634L,38635L,38636L,38637L,38638L,38639L,38640L,
92884 38641L,38642L,38643L,38644L,38645L,38646L,38647L,38648L,38649L,38650L,
92885 38651L,38652L,38653L,38654L,38655L,38656L,38657L,38658L,38659L,38660L,
92886 38661L,38662L,38663L,38664L,38665L,38666L,38667L,38668L,38669L,38670L,
92887 38671L,38672L,38673L,38674L,38675L,38676L,38677L,38678L,38679L,38680L,
92888 38681L,38682L,38683L,38684L,38685L,38686L,38687L,38688L,38689L,38690L,
92889 38691L,38692L,38693L,38694L,38695L,38696L,38697L,38698L,38699L,38700L,
92890 38701L,38702L,38703L,38704L,38705L,38706L,38707L,38708L,38709L,38710L,
92891 38711L,38712L,38713L,38714L,38715L,38716L,38717L,38718L,38719L,38720L,
92892 38721L,38722L,38723L,38724L,38725L,38726L,38727L,38728L,38729L,38730L,
92893 38731L,38732L,38733L,38734L,38735L,38736L,38737L,38738L,38739L,38740L,
92894 38741L,38742L,38743L,38744L,38745L,38746L,38747L,38748L,38749L,38750L,
92895 38751L,38752L,38753L,38754L,38755L,38756L,38757L,38758L,38759L,38760L,
92896 38761L,38762L,38763L,38764L,38765L,38766L,38767L,38768L,38769L,38770L,
92897 38771L,38772L,38773L,38774L,38775L,38776L,38777L,38778L,38779L,38780L,
92898 38781L,38782L,38783L,38784L,38785L,38786L,38787L,38788L,38789L,38790L,
92899 38791L,38792L,38793L,38794L,38795L,38796L,38797L,38798L,38799L,38800L,
92900 38801L,38802L,38803L,38804L,38805L,38806L,38807L,38808L,38809L,38810L,
92901 38811L,38812L,38813L,38814L,38815L,38816L,38817L,38818L,38819L,38820L,
92902 38821L,38822L,38823L,38824L,38825L,38826L,38827L,38828L,38829L,38830L,
92903 38831L,38832L,38833L,38834L,38835L,38836L,38837L,38838L,38839L,38840L,
92904 38841L,38842L,38843L,38844L,38845L,38846L,38847L,38848L,38849L,38850L,
92905 38851L,38852L,38853L,38854L,38855L,38856L,38857L,38858L,38859L,38860L,
92906 38861L,38862L,38863L,38864L,38865L,38866L,38867L,38868L,38869L,38870L,
92907 38871L,38872L,38873L,38874L,38875L,38876L,38877L,38878L,38879L,38880L,
92908 38881L,38882L,38883L,38884L,38885L,38886L,38887L,38888L,38889L,38890L,
92909 38891L,38892L,38893L,38894L,38895L,38896L,38897L,38898L,38899L,38900L,
92910 38901L,38902L,38903L,38904L,38905L,38906L,38907L,38908L,38909L,38910L,
92911 38911L,38912L,38913L,38914L,38915L,38916L,38917L,38918L,38919L,38920L,
92912 38921L,38922L,38923L,38924L,38925L,38926L,38927L,38928L,38929L,38930L,
92913 38931L,38932L,38933L,38934L,38935L,38936L,38937L,38938L,38939L,38940L,
92914 38941L,38942L,38943L,38944L,38945L,38946L,38947L,38948L,38949L,38950L,
92915 38951L,38952L,38953L,38954L,38955L,38956L,38957L,38958L,38959L,38960L,
92916 38961L,38962L,38963L,38964L,38965L,38966L,38967L,38968L,38969L,38970L,
92917 38971L,38972L,38973L,38974L,38975L,38976L,38977L,38978L,38979L,38980L,
92918 38981L,38982L,38983L,38984L,38985L,38986L,38987L,38988L,38989L,38990L,
92919 38991L,38992L,38993L,38994L,38995L,38996L,38997L,38998L,38999L,39000L,
92920 39001L,39002L,39003L,39004L,39005L,39006L,39007L,39008L,39009L,39010L,
92921 39011L,39012L,39013L,39014L,39015L,39016L,39017L,39018L,39019L,39020L,
92922 39021L,39022L,39023L,39024L,39025L,39026L,39027L,39028L,39029L,39030L,
92923 39031L,39032L,39033L,39034L,39035L,39036L,39037L,39038L,39039L,39040L,
92924 39041L,39042L,39043L,39044L,39045L,39046L,39047L,39048L,39049L,39050L,
92925 39051L,39052L,39053L,39054L,39055L,39056L,39057L,39058L,39059L,39060L,
92926 39061L,39062L,39063L,39064L,39065L,39066L,39067L,39068L,39069L,39070L,
92927 39071L,39072L,39073L,39074L,39075L,39076L,39077L,39078L,39079L,39080L,
92928 39081L,39082L,39083L,39084L,39085L,39086L,39087L,39088L,39089L,39090L,
92929 39091L,39092L,39093L,39094L,39095L,39096L,39097L,39098L,39099L,39100L,
92930 39101L,39102L,39103L,39104L,39105L,39106L,39107L,39108L,39109L,39110L,
92931 39111L,39112L,39113L,39114L,39115L,39116L,39117L,39118L,39119L,39120L,
92932 39121L,39122L,39123L,39124L,39125L,39126L,39127L,39128L,39129L,39130L,
92933 39131L,39132L,39133L,39134L,39135L,39136L,39137L,39138L,39139L,39140L,
92934 39141L,39142L,39143L,39144L,39145L,39146L,39147L,39148L,39149L,39150L,
92935 39151L,39152L,39153L,39154L,39155L,39156L,39157L,39158L,39159L,39160L,
92936 39161L,39162L,39163L,39164L,39165L,39166L,39167L,39168L,39169L,39170L,
92937 39171L,39172L,39173L,39174L,39175L,39176L,39177L,39178L,39179L,39180L,
92938 39181L,39182L,39183L,39184L,39185L,39186L,39187L,39188L,39189L,39190L,
92939 39191L,39192L,39193L,39194L,39195L,39196L,39197L,39198L,39199L,39200L,
92940 39201L,39202L,39203L,39204L,39205L,39206L,39207L,39208L,39209L,39210L,
92941 39211L,39212L,39213L,39214L,39215L,39216L,39217L,39218L,39219L,39220L,
92942 39221L,39222L,39223L,39224L,39225L,39226L,39227L,39228L,39229L,39230L,
92943 39231L,39232L,39233L,39234L,39235L,39236L,39237L,39238L,39239L,39240L,
92944 39241L,39242L,39243L,39244L,39245L,39246L,39247L,39248L,39249L,39250L,
92945 39251L,39252L,39253L,39254L,39255L,39256L,39257L,39258L,39259L,39260L,
92946 39261L,39262L,39263L,39264L,39265L,39266L,39267L,39268L,39269L,39270L,
92947 39271L,39272L,39273L,39274L,39275L,39276L,39277L,39278L,39279L,39280L,
92948 39281L,39282L,39283L,39284L,39285L,39286L,39287L,39288L,39289L,39290L,
92949 39291L,39292L,39293L,39294L,39295L,39296L,39297L,39298L,39299L,39300L,
92950 39301L,39302L,39303L,39304L,39305L,39306L,39307L,39308L,39309L,39310L,
92951 39311L,39312L,39313L,39314L,39315L,39316L,39317L,39318L,39319L,39320L,
92952 39321L,39322L,39323L,39324L,39325L,39326L,39327L,39328L,39329L,39330L,
92953 39331L,39332L,39333L,39334L,39335L,39336L,39337L,39338L,39339L,39340L,
92954 39341L,39342L,39343L,39344L,39345L,39346L,39347L,39348L,39349L,39350L,
92955 39351L,39352L,39353L,39354L,39355L,39356L,39357L,39358L,39359L,39360L,
92956 39361L,39362L,39363L,39364L,39365L,39366L,39367L,39368L,39369L,39370L,
92957 39371L,39372L,39373L,39374L,39375L,39376L,39377L,39378L,39379L,39380L,
92958 39381L,39382L,39383L,39384L,39385L,39386L,39387L,39388L,39389L,39390L,
92959 39391L,39392L,39393L,39394L,39395L,39396L,39397L,39398L,39399L,39400L,
92960 39401L,39402L,39403L,39404L,39405L,39406L,39407L,39408L,39409L,39410L,
92961 39411L,39412L,39413L,39414L,39415L,39416L,39417L,39418L,39419L,39420L,
92962 39421L,39422L,39423L,39424L,39425L,39426L,39427L,39428L,39429L,39430L,
92963 39431L,39432L,39433L,39434L,39435L,39436L,39437L,39438L,39439L,39440L,
92964 39441L,39442L,39443L,39444L,39445L,39446L,39447L,39448L,39449L,39450L,
92965 39451L,39452L,39453L,39454L,39455L,39456L,39457L,39458L,39459L,39460L,
92966 39461L,39462L,39463L,39464L,39465L,39466L,39467L,39468L,39469L,39470L,
92967 39471L,39472L,39473L,39474L,39475L,39476L,39477L,39478L,39479L,39480L,
92968 39481L,39482L,39483L,39484L,39485L,39486L,39487L,39488L,39489L,39490L,
92969 39491L,39492L,39493L,39494L,39495L,39496L,39497L,39498L,39499L,39500L,
92970 39501L,39502L,39503L,39504L,39505L,39506L,39507L,39508L,39509L,39510L,
92971 39511L,39512L,39513L,39514L,39515L,39516L,39517L,39518L,39519L,39520L,
92972 39521L,39522L,39523L,39524L,39525L,39526L,39527L,39528L,39529L,39530L,
92973 39531L,39532L,39533L,39534L,39535L,39536L,39537L,39538L,39539L,39540L,
92974 39541L,39542L,39543L,39544L,39545L,39546L,39547L,39548L,39549L,39550L,
92975 39551L,39552L,39553L,39554L,39555L,39556L,39557L,39558L,39559L,39560L,
92976 39561L,39562L,39563L,39564L,39565L,39566L,39567L,39568L,39569L,39570L,
92977 39571L,39572L,39573L,39574L,39575L,39576L,39577L,39578L,39579L,39580L,
92978 39581L,39582L,39583L,39584L,39585L,39586L,39587L,39588L,39589L,39590L,
92979 39591L,39592L,39593L,39594L,39595L,39596L,39597L,39598L,39599L,39600L,
92980 39601L,39602L,39603L,39604L,39605L,39606L,39607L,39608L,39609L,39610L,
92981 39611L,39612L,39613L,39614L,39615L,39616L,39617L,39618L,39619L,39620L,
92982 39621L,39622L,39623L,39624L,39625L,39626L,39627L,39628L,39629L,39630L,
92983 39631L,39632L,39633L,39634L,39635L,39636L,39637L,39638L,39639L,39640L,
92984 39641L,39642L,39643L,39644L,39645L,39646L,39647L,39648L,39649L,39650L,
92985 39651L,39652L,39653L,39654L,39655L,39656L,39657L,39658L,39659L,39660L,
92986 39661L,39662L,39663L,39664L,39665L,39666L,39667L,39668L,39669L,39670L,
92987 39671L,39672L,39673L,39674L,39675L,39676L,39677L,39678L,39679L,39680L,
92988 39681L,39682L,39683L,39684L,39685L,39686L,39687L,39688L,39689L,39690L,
92989 39691L,39692L,39693L,39694L,39695L,39696L,39697L,39698L,39699L,39700L,
92990 39701L,39702L,39703L,39704L,39705L,39706L,39707L,39708L,39709L,39710L,
92991 39711L,39712L,39713L,39714L,39715L,39716L,39717L,39718L,39719L,39720L,
92992 39721L,39722L,39723L,39724L,39725L,39726L,39727L,39728L,39729L,39730L,
92993 39731L,39732L,39733L,39734L,39735L,39736L,39737L,39738L,39739L,39740L,
92994 39741L,39742L,39743L,39744L,39745L,39746L,39747L,39748L,39749L,39750L,
92995 39751L,39752L,39753L,39754L,39755L,39756L,39757L,39758L,39759L,39760L,
92996 39761L,39762L,39763L,39764L,39765L,39766L,39767L,39768L,39769L,39770L,
92997 39771L,39772L,39773L,39774L,39775L,39776L,39777L,39778L,39779L,39780L,
92998 39781L,39782L,39783L,39784L,39785L,39786L,39787L,39788L,39789L,39790L,
92999 39791L,39792L,39793L,39794L,39795L,39796L,39797L,39798L,39799L,39800L,
93000 39801L,39802L,39803L,39804L,39805L,39806L,39807L,39808L,39809L,39810L,
93001 39811L,39812L,39813L,39814L,39815L,39816L,39817L,39818L,39819L,39820L,
93002 39821L,39822L,39823L,39824L,39825L,39826L,39827L,39828L,39829L,39830L,
93003 39831L,39832L,39833L,39834L,39835L,39836L,39837L,39838L,39839L,39840L,
93004 39841L,39842L,39843L,39844L,39845L,39846L,39847L,39848L,39849L,39850L,
93005 39851L,39852L,39853L,39854L,39855L,39856L,39857L,39858L,39859L,39860L,
93006 39861L,39862L,39863L,39864L,39865L,39866L,39867L,39868L,39869L,39870L,
93007 39871L,39872L,39873L,39874L,39875L,39876L,39877L,39878L,39879L,39880L,
93008 39881L,39882L,39883L,39884L,39885L,39886L,39887L,39888L,39889L,39890L,
93009 39891L,39892L,39893L,39894L,39895L,39896L,39897L,39898L,39899L,39900L,
93010 39901L,39902L,39903L,39904L,39905L,39906L,39907L,39908L,39909L,39910L,
93011 39911L,39912L,39913L,39914L,39915L,39916L,39917L,39918L,39919L,39920L,
93012 39921L,39922L,39923L,39924L,39925L,39926L,39927L,39928L,39929L,39930L,
93013 39931L,39932L,39933L,39934L,39935L,39936L,39937L,39938L,39939L,39940L,
93014 39941L,39942L,39943L,39944L,39945L,39946L,39947L,39948L,39949L,39950L,
93015 39951L,39952L,39953L,39954L,39955L,39956L,39957L,39958L,39959L,39960L,
93016 39961L,39962L,39963L,39964L,39965L,39966L,39967L,39968L,39969L,39970L,
93017 39971L,39972L,39973L,39974L,39975L,39976L,39977L,39978L,39979L,39980L,
93018 39981L,39982L,39983L,39984L,39985L,39986L,39987L,39988L,39989L,39990L,
93019 39991L,39992L,39993L,39994L,39995L,39996L,39997L,39998L,39999L,40000L,
93020 40001L,40002L,40003L,40004L,40005L,40006L,40007L,40008L,40009L,40010L,
93021 40011L,40012L,40013L,40014L,40015L,40016L,40017L,40018L,40019L,40020L,
93022 40021L,40022L,40023L,40024L,40025L,40026L,40027L,40028L,40029L,40030L,
93023 40031L,40032L,40033L,40034L,40035L,40036L,40037L,40038L,40039L,40040L,
93024 40041L,40042L,40043L,40044L,40045L,40046L,40047L,40048L,40049L,40050L,
93025 40051L,40052L,40053L,40054L,40055L,40056L,40057L,40058L,40059L,40060L,
93026 40061L,40062L,40063L,40064L,40065L,40066L,40067L,40068L,40069L,40070L,
93027 40071L,40072L,40073L,40074L,40075L,40076L,40077L,40078L,40079L,40080L,
93028 40081L,40082L,40083L,40084L,40085L,40086L,40087L,40088L,40089L,40090L,
93029 40091L,40092L,40093L,40094L,40095L,40096L,40097L,40098L,40099L,40100L,
93030 40101L,40102L,40103L,40104L,40105L,40106L,40107L,40108L,40109L,40110L,
93031 40111L,40112L,40113L,40114L,40115L,40116L,40117L,40118L,40119L,40120L,
93032 40121L,40122L,40123L,40124L,40125L,40126L,40127L,40128L,40129L,40130L,
93033 40131L,40132L,40133L,40134L,40135L,40136L,40137L,40138L,40139L,40140L,
93034 40141L,40142L,40143L,40144L,40145L,40146L,40147L,40148L,40149L,40150L,
93035 40151L,40152L,40153L,40154L,40155L,40156L,40157L,40158L,40159L,40160L,
93036 40161L,40162L,40163L,40164L,40165L,40166L,40167L,40168L,40169L,40170L,
93037 40171L,40172L,40173L,40174L,40175L,40176L,40177L,40178L,40179L,40180L,
93038 40181L,40182L,40183L,40184L,40185L,40186L,40187L,40188L,40189L,40190L,
93039 40191L,40192L,40193L,40194L,40195L,40196L,40197L,40198L,40199L,40200L,
93040 40201L,40202L,40203L,40204L,40205L,40206L,40207L,40208L,40209L,40210L,
93041 40211L,40212L,40213L,40214L,40215L,40216L,40217L,40218L,40219L,40220L,
93042 40221L,40222L,40223L,40224L,40225L,40226L,40227L,40228L,40229L,40230L,
93043 40231L,40232L,40233L,40234L,40235L,40236L,40237L,40238L,40239L,40240L,
93044 40241L,40242L,40243L,40244L,40245L,40246L,40247L,40248L,40249L,40250L,
93045 40251L,40252L,40253L,40254L,40255L,40256L,40257L,40258L,40259L,40260L,
93046 40261L,40262L,40263L,40264L,40265L,40266L,40267L,40268L,40269L,40270L,
93047 40271L,40272L,40273L,40274L,40275L,40276L,40277L,40278L,40279L,40280L,
93048 40281L,40282L,40283L,40284L,40285L,40286L,40287L,40288L,40289L,40290L,
93049 40291L,40292L,40293L,40294L,40295L,40296L,40297L,40298L,40299L,40300L,
93050 40301L,40302L,40303L,40304L,40305L,40306L,40307L,40308L,40309L,40310L,
93051 40311L,40312L,40313L,40314L,40315L,40316L,40317L,40318L,40319L,40320L,
93052 40321L,40322L,40323L,40324L,40325L,40326L,40327L,40328L,40329L,40330L,
93053 40331L,40332L,40333L,40334L,40335L,40336L,40337L,40338L,40339L,40340L,
93054 40341L,40342L,40343L,40344L,40345L,40346L,40347L,40348L,40349L,40350L,
93055 40351L,40352L,40353L,40354L,40355L,40356L,40357L,40358L,40359L,40360L,
93056 40361L,40362L,40363L,40364L,40365L,40366L,40367L,40368L,40369L,40370L,
93057 40371L,40372L,40373L,40374L,40375L,40376L,40377L,40378L,40379L,40380L,
93058 40381L,40382L,40383L,40384L,40385L,40386L,40387L,40388L,40389L,40390L,
93059 40391L,40392L,40393L,40394L,40395L,40396L,40397L,40398L,40399L,40400L,
93060 40401L,40402L,40403L,40404L,40405L,40406L,40407L,40408L,40409L,40410L,
93061 40411L,40412L,40413L,40414L,40415L,40416L,40417L,40418L,40419L,40420L,
93062 40421L,40422L,40423L,40424L,40425L,40426L,40427L,40428L,40429L,40430L,
93063 40431L,40432L,40433L,40434L,40435L,40436L,40437L,40438L,40439L,40440L,
93064 40441L,40442L,40443L,40444L,40445L,40446L,40447L,40448L,40449L,40450L,
93065 40451L,40452L,40453L,40454L,40455L,40456L,40457L,40458L,40459L,40460L,
93066 40461L,40462L,40463L,40464L,40465L,40466L,40467L,40468L,40469L,40470L,
93067 40471L,40472L,40473L,40474L,40475L,40476L,40477L,40478L,40479L,40480L,
93068 40481L,40482L,40483L,40484L,40485L,40486L,40487L,40488L,40489L,40490L,
93069 40491L,40492L,40493L,40494L,40495L,40496L,40497L,40498L,40499L,40500L,
93070 40501L,40502L,40503L,40504L,40505L,40506L,40507L,40508L,40509L,40510L,
93071 40511L,40512L,40513L,40514L,40515L,40516L,40517L,40518L,40519L,40520L,
93072 40521L,40522L,40523L,40524L,40525L,40526L,40527L,40528L,40529L,40530L,
93073 40531L,40532L,40533L,40534L,40535L,40536L,40537L,40538L,40539L,40540L,
93074 40541L,40542L,40543L,40544L,40545L,40546L,40547L,40548L,40549L,40550L,
93075 40551L,40552L,40553L,40554L,40555L,40556L,40557L,40558L,40559L,40560L,
93076 40561L,40562L,40563L,40564L,40565L,40566L,40567L,40568L,40569L,40570L,
93077 40571L,40572L,40573L,40574L,40575L,40576L,40577L,40578L,40579L,40580L,
93078 40581L,40582L,40583L,40584L,40585L,40586L,40587L,40588L,40589L,40590L,
93079 40591L,40592L,40593L,40594L,40595L,40596L,40597L,40598L,40599L,40600L,
93080 40601L,40602L,40603L,40604L,40605L,40606L,40607L,40608L,40609L,40610L,
93081 40611L,40612L,40613L,40614L,40615L,40616L,40617L,40618L,40619L,40620L,
93082 40621L,40622L,40623L,40624L,40625L,40626L,40627L,40628L,40629L,40630L,
93083 40631L,40632L,40633L,40634L,40635L,40636L,40637L,40638L,40639L,40640L,
93084 40641L,40642L,40643L,40644L,40645L,40646L,40647L,40648L,40649L,40650L,
93085 40651L,40652L,40653L,40654L,40655L,40656L,40657L,40658L,40659L,40660L,
93086 40661L,40662L,40663L,40664L,40665L,40666L,40667L,40668L,40669L,40670L,
93087 40671L,40672L,40673L,40674L,40675L,40676L,40677L,40678L,40679L,40680L,
93088 40681L,40682L,40683L,40684L,40685L,40686L,40687L,40688L,40689L,40690L,
93089 40691L,40692L,40693L,40694L,40695L,40696L,40697L,40698L,40699L,40700L,
93090 40701L,40702L,40703L,40704L,40705L,40706L,40707L,40708L,40709L,40710L,
93091 40711L,40712L,40713L,40714L,40715L,40716L,40717L,40718L,40719L,40720L,
93092 40721L,40722L,40723L,40724L,40725L,40726L,40727L,40728L,40729L,40730L,
93093 40731L,40732L,40733L,40734L,40735L,40736L,40737L,40738L,40739L,40740L,
93094 40741L,40742L,40743L,40744L,40745L,40746L,40747L,40748L,40749L,40750L,
93095 40751L,40752L,40753L,40754L,40755L,40756L,40757L,40758L,40759L,40760L,
93096 40761L,40762L,40763L,40764L,40765L,40766L,40767L,40768L,40769L,40770L,
93097 40771L,40772L,40773L,40774L,40775L,40776L,40777L,40778L,40779L,40780L,
93098 40781L,40782L,40783L,40784L,40785L,40786L,40787L,40788L,40789L,40790L,
93099 40791L,40792L,40793L,40794L,40795L,40796L,40797L,40798L,40799L,40800L,
93100 40801L,40802L,40803L,40804L,40805L,40806L,40807L,40808L,40809L,40810L,
93101 40811L,40812L,40813L,40814L,40815L,40816L,40817L,40818L,40819L,40820L,
93102 40821L,40822L,40823L,40824L,40825L,40826L,40827L,40828L,40829L,40830L,
93103 40831L,40832L,40833L,40834L,40835L,40836L,40837L,40838L,40839L,40840L,
93104 40841L,40842L,40843L,40844L,40845L,40846L,40847L,40848L,40849L,40850L,
93105 40851L,40852L,40853L,40854L,40855L,40856L,40857L,40858L,40859L,40860L,
93106 40861L,40862L,40863L,40864L,40865L,40866L,40867L,40868L,40869L,40870L,
93107 40871L,40872L,40873L,40874L,40875L,40876L,40877L,40878L,40879L,40880L,
93108 40881L,40882L,40883L,40884L,40885L,40886L,40887L,40888L,40889L,40890L,
93109 40891L,40892L,40893L,40894L,40895L,40896L,40897L,40898L,40899L,40900L,
93110 40901L,40902L,40903L,40904L,40905L,40906L,40907L,40908L,40909L,40910L,
93111 40911L,40912L,40913L,40914L,40915L,40916L,40917L,40918L,40919L,40920L,
93112 40921L,40922L,40923L,40924L,40925L,40926L,40927L,40928L,40929L,40930L,
93113 40931L,40932L,40933L,40934L,40935L,40936L,40937L,40938L,40939L,40940L,
93114 40941L,40942L,40943L,40944L,40945L,40946L,40947L,40948L,40949L,40950L,
93115 40951L,40952L,40953L,40954L,40955L,40956L,40957L,40958L,40959L,40960L,
93116 40961L,40962L,40963L,40964L,40965L,40966L,40967L,40968L,40969L,40970L,
93117 40971L,40972L,40973L,40974L,40975L,40976L,40977L,40978L,40979L,40980L,
93118 40981L,40982L,40983L,40984L,40985L,40986L,40987L,40988L,40989L,40990L,
93119 40991L,40992L,40993L,40994L,40995L,40996L,40997L,40998L,40999L,41000L,
93120 41001L,41002L,41003L,41004L,41005L,41006L,41007L,41008L,41009L,41010L,
93121 41011L,41012L,41013L,41014L,41015L,41016L,41017L,41018L,41019L,41020L,
93122 41021L,41022L,41023L,41024L,41025L,41026L,41027L,41028L,41029L,41030L,
93123 41031L,41032L,41033L,41034L,41035L,41036L,41037L,41038L,41039L,41040L,
93124 41041L,41042L,41043L,41044L,41045L,41046L,41047L,41048L,41049L,41050L,
93125 41051L,41052L,41053L,41054L,41055L,41056L,41057L,41058L,41059L,41060L,
93126 41061L,41062L,41063L,41064L,41065L,41066L,41067L,41068L,41069L,41070L,
93127 41071L,41072L,41073L,41074L,41075L,41076L,41077L,41078L,41079L,41080L,
93128 41081L,41082L,41083L,41084L,41085L,41086L,41087L,41088L,41089L,41090L,
93129 41091L,41092L,41093L,41094L,41095L,41096L,41097L,41098L,41099L,41100L,
93130 41101L,41102L,41103L,41104L,41105L,41106L,41107L,41108L,41109L,41110L,
93131 41111L,41112L,41113L,41114L,41115L,41116L,41117L,41118L,41119L,41120L,
93132 41121L,41122L,41123L,41124L,41125L,41126L,41127L,41128L,41129L,41130L,
93133 41131L,41132L,41133L,41134L,41135L,41136L,41137L,41138L,41139L,41140L,
93134 41141L,41142L,41143L,41144L,41145L,41146L,41147L,41148L,41149L,41150L,
93135 41151L,41152L,41153L,41154L,41155L,41156L,41157L,41158L,41159L,41160L,
93136 41161L,41162L,41163L,41164L,41165L,41166L,41167L,41168L,41169L,41170L,
93137 41171L,41172L,41173L,41174L,41175L,41176L,41177L,41178L,41179L,41180L,
93138 41181L,41182L,41183L,41184L,41185L,41186L,41187L,41188L,41189L,41190L,
93139 41191L,41192L,41193L,41194L,41195L,41196L,41197L,41198L,41199L,41200L,
93140 41201L,41202L,41203L,41204L,41205L,41206L,41207L,41208L,41209L,41210L,
93141 41211L,41212L,41213L,41214L,41215L,41216L,41217L,41218L,41219L,41220L,
93142 41221L,41222L,41223L,41224L,41225L,41226L,41227L,41228L,41229L,41230L,
93143 41231L,41232L,41233L,41234L,41235L,41236L,41237L,41238L,41239L,41240L,
93144 41241L,41242L,41243L,41244L,41245L,41246L,41247L,41248L,41249L,41250L,
93145 41251L,41252L,41253L,41254L,41255L,41256L,41257L,41258L,41259L,41260L,
93146 41261L,41262L,41263L,41264L,41265L,41266L,41267L,41268L,41269L,41270L,
93147 41271L,41272L,41273L,41274L,41275L,41276L,41277L,41278L,41279L,41280L,
93148 41281L,41282L,41283L,41284L,41285L,41286L,41287L,41288L,41289L,41290L,
93149 41291L,41292L,41293L,41294L,41295L,41296L,41297L,41298L,41299L,41300L,
93150 41301L,41302L,41303L,41304L,41305L,41306L,41307L,41308L,41309L,41310L,
93151 41311L,41312L,41313L,41314L,41315L,41316L,41317L,41318L,41319L,41320L,
93152 41321L,41322L,41323L,41324L,41325L,41326L,41327L,41328L,41329L,41330L,
93153 41331L,41332L,41333L,41334L,41335L,41336L,41337L,41338L,41339L,41340L,
93154 41341L,41342L,41343L,41344L,41345L,41346L,41347L,41348L,41349L,41350L,
93155 41351L,41352L,41353L,41354L,41355L,41356L,41357L,41358L,41359L,41360L,
93156 41361L,41362L,41363L,41364L,41365L,41366L,41367L,41368L,41369L,41370L,
93157 41371L,41372L,41373L,41374L,41375L,41376L,41377L,41378L,41379L,41380L,
93158 41381L,41382L,41383L,41384L,41385L,41386L,41387L,41388L,41389L,41390L,
93159 41391L,41392L,41393L,41394L,41395L,41396L,41397L,41398L,41399L,41400L,
93160 41401L,41402L,41403L,41404L,41405L,41406L,41407L,41408L,41409L,41410L,
93161 41411L,41412L,41413L,41414L,41415L,41416L,41417L,41418L,41419L,41420L,
93162 41421L,41422L,41423L,41424L,41425L,41426L,41427L,41428L,41429L,41430L,
93163 41431L,41432L,41433L,41434L,41435L,41436L,41437L,41438L,41439L,41440L,
93164 41441L,41442L,41443L,41444L,41445L,41446L,41447L,41448L,41449L,41450L,
93165 41451L,41452L,41453L,41454L,41455L,41456L,41457L,41458L,41459L,41460L,
93166 41461L,41462L,41463L,41464L,41465L,41466L,41467L,41468L,41469L,41470L,
93167 41471L,41472L,41473L,41474L,41475L,41476L,41477L,41478L,41479L,41480L,
93168 41481L,41482L,41483L,41484L,41485L,41486L,41487L,41488L,41489L,41490L,
93169 41491L,41492L,41493L,41494L,41495L,41496L,41497L,41498L,41499L,41500L,
93170 41501L,41502L,41503L,41504L,41505L,41506L,41507L,41508L,41509L,41510L,
93171 41511L,41512L,41513L,41514L,41515L,41516L,41517L,41518L,41519L,41520L,
93172 41521L,41522L,41523L,41524L,41525L,41526L,41527L,41528L,41529L,41530L,
93173 41531L,41532L,41533L,41534L,41535L,41536L,41537L,41538L,41539L,41540L,
93174 41541L,41542L,41543L,41544L,41545L,41546L,41547L,41548L,41549L,41550L,
93175 41551L,41552L,41553L,41554L,41555L,41556L,41557L,41558L,41559L,41560L,
93176 41561L,41562L,41563L,41564L,41565L,41566L,41567L,41568L,41569L,41570L,
93177 41571L,41572L,41573L,41574L,41575L,41576L,41577L,41578L,41579L,41580L,
93178 41581L,41582L,41583L,41584L,41585L,41586L,41587L,41588L,41589L,41590L,
93179 41591L,41592L,41593L,41594L,41595L,41596L,41597L,41598L,41599L,41600L,
93180 41601L,41602L,41603L,41604L,41605L,41606L,41607L,41608L,41609L,41610L,
93181 41611L,41612L,41613L,41614L,41615L,41616L,41617L,41618L,41619L,41620L,
93182 41621L,41622L,41623L,41624L,41625L,41626L,41627L,41628L,41629L,41630L,
93183 41631L,41632L,41633L,41634L,41635L,41636L,41637L,41638L,41639L,41640L,
93184 41641L,41642L,41643L,41644L,41645L,41646L,41647L,41648L,41649L,41650L,
93185 41651L,41652L,41653L,41654L,41655L,41656L,41657L,41658L,41659L,41660L,
93186 41661L,41662L,41663L,41664L,41665L,41666L,41667L,41668L,41669L,41670L,
93187 41671L,41672L,41673L,41674L,41675L,41676L,41677L,41678L,41679L,41680L,
93188 41681L,41682L,41683L,41684L,41685L,41686L,41687L,41688L,41689L,41690L,
93189 41691L,41692L,41693L,41694L,41695L,41696L,41697L,41698L,41699L,41700L,
93190 41701L,41702L,41703L,41704L,41705L,41706L,41707L,41708L,41709L,41710L,
93191 41711L,41712L,41713L,41714L,41715L,41716L,41717L,41718L,41719L,41720L,
93192 41721L,41722L,41723L,41724L,41725L,41726L,41727L,41728L,41729L,41730L,
93193 41731L,41732L,41733L,41734L,41735L,41736L,41737L,41738L,41739L,41740L,
93194 41741L,41742L,41743L,41744L,41745L,41746L,41747L,41748L,41749L,41750L,
93195 41751L,41752L,41753L,41754L,41755L,41756L,41757L,41758L,41759L,41760L,
93196 41761L,41762L,41763L,41764L,41765L,41766L,41767L,41768L,41769L,41770L,
93197 41771L,41772L,41773L,41774L,41775L,41776L,41777L,41778L,41779L,41780L,
93198 41781L,41782L,41783L,41784L,41785L,41786L,41787L,41788L,41789L,41790L,
93199 41791L,41792L,41793L,41794L,41795L,41796L,41797L,41798L,41799L,41800L,
93200 41801L,41802L,41803L,41804L,41805L,41806L,41807L,41808L,41809L,41810L,
93201 41811L,41812L,41813L,41814L,41815L,41816L,41817L,41818L,41819L,41820L,
93202 41821L,41822L,41823L,41824L,41825L,41826L,41827L,41828L,41829L,41830L,
93203 41831L,41832L,41833L,41834L,41835L,41836L,41837L,41838L,41839L,41840L,
93204 41841L,41842L,41843L,41844L,41845L,41846L,41847L,41848L,41849L,41850L,
93205 41851L,41852L,41853L,41854L,41855L,41856L,41857L,41858L,41859L,41860L,
93206 41861L,41862L,41863L,41864L,41865L,41866L,41867L,41868L,41869L,41870L,
93207 41871L,41872L,41873L,41874L,41875L,41876L,41877L,41878L,41879L,41880L,
93208 41881L,41882L,41883L,41884L,41885L,41886L,41887L,41888L,41889L,41890L,
93209 41891L,41892L,41893L,41894L,41895L,41896L,41897L,41898L,41899L,41900L,
93210 41901L,41902L,41903L,41904L,41905L,41906L,41907L,41908L,41909L,41910L,
93211 41911L,41912L,41913L,41914L,41915L,41916L,41917L,41918L,41919L,41920L,
93212 41921L,41922L,41923L,41924L,41925L,41926L,41927L,41928L,41929L,41930L,
93213 41931L,41932L,41933L,41934L,41935L,41936L,41937L,41938L,41939L,41940L,
93214 41941L,41942L,41943L,41944L,41945L,41946L,41947L,41948L,41949L,41950L,
93215 41951L,41952L,41953L,41954L,41955L,41956L,41957L,41958L,41959L,41960L,
93216 41961L,41962L,41963L,41964L,41965L,41966L,41967L,41968L,41969L,41970L,
93217 41971L,41972L,41973L,41974L,41975L,41976L,41977L,41978L,41979L,41980L,
93218 41981L,41982L,41983L,41984L,41985L,41986L,41987L,41988L,41989L,41990L,
93219 41991L,41992L,41993L,41994L,41995L,41996L,41997L,41998L,41999L,42000L,
93220 42001L,42002L,42003L,42004L,42005L,42006L,42007L,42008L,42009L,42010L,
93221 42011L,42012L,42013L,42014L,42015L,42016L,42017L,42018L,42019L,42020L,
93222 42021L,42022L,42023L,42024L,42025L,42026L,42027L,42028L,42029L,42030L,
93223 42031L,42032L,42033L,42034L,42035L,42036L,42037L,42038L,42039L,42040L,
93224 42041L,42042L,42043L,42044L,42045L,42046L,42047L,42048L,42049L,42050L,
93225 42051L,42052L,42053L,42054L,42055L,42056L,42057L,42058L,42059L,42060L,
93226 42061L,42062L,42063L,42064L,42065L,42066L,42067L,42068L,42069L,42070L,
93227 42071L,42072L,42073L,42074L,42075L,42076L,42077L,42078L,42079L,42080L,
93228 42081L,42082L,42083L,42084L,42085L,42086L,42087L,42088L,42089L,42090L,
93229 42091L,42092L,42093L,42094L,42095L,42096L,42097L,42098L,42099L,42100L,
93230 42101L,42102L,42103L,42104L,42105L,42106L,42107L,42108L,42109L,42110L,
93231 42111L,42112L,42113L,42114L,42115L,42116L,42117L,42118L,42119L,42120L,
93232 42121L,42122L,42123L,42124L,42125L,42126L,42127L,42128L,42129L,42130L,
93233 42131L,42132L,42133L,42134L,42135L,42136L,42137L,42138L,42139L,42140L,
93234 42141L,42142L,42143L,42144L,42145L,42146L,42147L,42148L,42149L,42150L,
93235 42151L,42152L,42153L,42154L,42155L,42156L,42157L,42158L,42159L,42160L,
93236 42161L,42162L,42163L,42164L,42165L,42166L,42167L,42168L,42169L,42170L,
93237 42171L,42172L,42173L,42174L,42175L,42176L,42177L,42178L,42179L,42180L,
93238 42181L,42182L,42183L,42184L,42185L,42186L,42187L,42188L,42189L,42190L,
93239 42191L,42192L,42193L,42194L,42195L,42196L,42197L,42198L,42199L,42200L,
93240 42201L,42202L,42203L,42204L,42205L,42206L,42207L,42208L,42209L,42210L,
93241 42211L,42212L,42213L,42214L,42215L,42216L,42217L,42218L,42219L,42220L,
93242 42221L,42222L,42223L,42224L,42225L,42226L,42227L,42228L,42229L,42230L,
93243 42231L,42232L,42233L,42234L,42235L,42236L,42237L,42238L,42239L,42240L,
93244 42241L,42242L,42243L,42244L,42245L,42246L,42247L,42248L,42249L,42250L,
93245 42251L,42252L,42253L,42254L,42255L,42256L,42257L,42258L,42259L,42260L,
93246 42261L,42262L,42263L,42264L,42265L,42266L,42267L,42268L,42269L,42270L,
93247 42271L,42272L,42273L,42274L,42275L,42276L,42277L,42278L,42279L,42280L,
93248 42281L,42282L,42283L,42284L,42285L,42286L,42287L,42288L,42289L,42290L,
93249 42291L,42292L,42293L,42294L,42295L,42296L,42297L,42298L,42299L,42300L,
93250 42301L,42302L,42303L,42304L,42305L,42306L,42307L,42308L,42309L,42310L,
93251 42311L,42312L,42313L,42314L,42315L,42316L,42317L,42318L,42319L,42320L,
93252 42321L,42322L,42323L,42324L,42325L,42326L,42327L,42328L,42329L,42330L,
93253 42331L,42332L,42333L,42334L,42335L,42336L,42337L,42338L,42339L,42340L,
93254 42341L,42342L,42343L,42344L,42345L,42346L,42347L,42348L,42349L,42350L,
93255 42351L,42352L,42353L,42354L,42355L,42356L,42357L,42358L,42359L,42360L,
93256 42361L,42362L,42363L,42364L,42365L,42366L,42367L,42368L,42369L,42370L,
93257 42371L,42372L,42373L,42374L,42375L,42376L,42377L,42378L,42379L,42380L,
93258 42381L,42382L,42383L,42384L,42385L,42386L,42387L,42388L,42389L,42390L,
93259 42391L,42392L,42393L,42394L,42395L,42396L,42397L,42398L,42399L,42400L,
93260 42401L,42402L,42403L,42404L,42405L,42406L,42407L,42408L,42409L,42410L,
93261 42411L,42412L,42413L,42414L,42415L,42416L,42417L,42418L,42419L,42420L,
93262 42421L,42422L,42423L,42424L,42425L,42426L,42427L,42428L,42429L,42430L,
93263 42431L,42432L,42433L,42434L,42435L,42436L,42437L,42438L,42439L,42440L,
93264 42441L,42442L,42443L,42444L,42445L,42446L,42447L,42448L,42449L,42450L,
93265 42451L,42452L,42453L,42454L,42455L,42456L,42457L,42458L,42459L,42460L,
93266 42461L,42462L,42463L,42464L,42465L,42466L,42467L,42468L,42469L,42470L,
93267 42471L,42472L,42473L,42474L,42475L,42476L,42477L,42478L,42479L,42480L,
93268 42481L,42482L,42483L,42484L,42485L,42486L,42487L,42488L,42489L,42490L,
93269 42491L,42492L,42493L,42494L,42495L,42496L,42497L,42498L,42499L,42500L,
93270 42501L,42502L,42503L,42504L,42505L,42506L,42507L,42508L,42509L,42510L,
93271 42511L,42512L,42513L,42514L,42515L,42516L,42517L,42518L,42519L,42520L,
93272 42521L,42522L,42523L,42524L,42525L,42526L,42527L,42528L,42529L,42530L,
93273 42531L,42532L,42533L,42534L,42535L,42536L,42537L,42538L,42539L,42540L,
93274 42541L,42542L,42543L,42544L,42545L,42546L,42547L,42548L,42549L,42550L,
93275 42551L,42552L,42553L,42554L,42555L,42556L,42557L,42558L,42559L,42560L,
93276 42560L,42562L,42562L,42564L,42564L,42566L,42566L,42568L,42568L,42570L,
93277 42570L,42572L,42572L,42574L,42574L,42576L,42576L,42578L,42578L,42580L,
93278 42580L,42582L,42582L,42584L,42584L,42586L,42586L,42588L,42588L,42590L,
93279 42590L,42592L,42592L,42594L,42594L,42596L,42596L,42598L,42598L,42600L,
93280 42600L,42602L,42602L,42604L,42604L,42606L,42607L,42608L,42609L,42610L,
93281 42611L,42612L,42613L,42614L,42615L,42616L,42617L,42618L,42619L,42620L,
93282 42621L,42622L,42623L,42624L,42624L,42626L,42626L,42628L,42628L,42630L,
93283 42630L,42632L,42632L,42634L,42634L,42636L,42636L,42638L,42638L,42640L,
93284 42640L,42642L,42642L,42644L,42644L,42646L,42646L,42648L,42648L,42650L,
93285 42650L,42652L,42653L,42654L,42655L,42656L,42657L,42658L,42659L,42660L,
93286 42661L,42662L,42663L,42664L,42665L,42666L,42667L,42668L,42669L,42670L,
93287 42671L,42672L,42673L,42674L,42675L,42676L,42677L,42678L,42679L,42680L,
93288 42681L,42682L,42683L,42684L,42685L,42686L,42687L,42688L,42689L,42690L,
93289 42691L,42692L,42693L,42694L,42695L,42696L,42697L,42698L,42699L,42700L,
93290 42701L,42702L,42703L,42704L,42705L,42706L,42707L,42708L,42709L,42710L,
93291 42711L,42712L,42713L,42714L,42715L,42716L,42717L,42718L,42719L,42720L,
93292 42721L,42722L,42723L,42724L,42725L,42726L,42727L,42728L,42729L,42730L,
93293 42731L,42732L,42733L,42734L,42735L,42736L,42737L,42738L,42739L,42740L,
93294 42741L,42742L,42743L,42744L,42745L,42746L,42747L,42748L,42749L,42750L,
93295 42751L,42752L,42753L,42754L,42755L,42756L,42757L,42758L,42759L,42760L,
93296 42761L,42762L,42763L,42764L,42765L,42766L,42767L,42768L,42769L,42770L,
93297 42771L,42772L,42773L,42774L,42775L,42776L,42777L,42778L,42779L,42780L,
93298 42781L,42782L,42783L,42784L,42785L,42786L,42786L,42788L,42788L,42790L,
93299 42790L,42792L,42792L,42794L,42794L,42796L,42796L,42798L,42798L,42800L,
93300 42801L,42802L,42802L,42804L,42804L,42806L,42806L,42808L,42808L,42810L,
93301 42810L,42812L,42812L,42814L,42814L,42816L,42816L,42818L,42818L,42820L,
93302 42820L,42822L,42822L,42824L,42824L,42826L,42826L,42828L,42828L,42830L,
93303 42830L,42832L,42832L,42834L,42834L,42836L,42836L,42838L,42838L,42840L,
93304 42840L,42842L,42842L,42844L,42844L,42846L,42846L,42848L,42848L,42850L,
93305 42850L,42852L,42852L,42854L,42854L,42856L,42856L,42858L,42858L,42860L,
93306 42860L,42862L,42862L,42864L,42865L,42866L,42867L,42868L,42869L,42870L,
93307 42871L,42872L,42873L,42873L,42875L,42875L,42877L,42878L,42878L,42880L,
93308 42880L,42882L,42882L,42884L,42884L,42886L,42886L,42888L,42889L,42890L,
93309 42891L,42891L,42893L,42894L,42895L,42896L,42896L,42898L,42898L,42900L,
93310 42901L,42902L,42902L,42904L,42904L,42906L,42906L,42908L,42908L,42910L,
93311 42910L,42912L,42912L,42914L,42914L,42916L,42916L,42918L,42918L,42920L,
93312 42920L,42922L,42923L,42924L,42925L,42926L,42927L,42928L,42929L,42930L,
93313 42931L,42932L,42932L,42934L,42934L,42936L,42937L,42938L,42939L,42940L,
93314 42941L,42942L,42943L,42944L,42945L,42946L,42947L,42948L,42949L,42950L,
93315 42951L,42952L,42953L,42954L,42955L,42956L,42957L,42958L,42959L,42960L,
93316 42961L,42962L,42963L,42964L,42965L,42966L,42967L,42968L,42969L,42970L,
93317 42971L,42972L,42973L,42974L,42975L,42976L,42977L,42978L,42979L,42980L,
93318 42981L,42982L,42983L,42984L,42985L,42986L,42987L,42988L,42989L,42990L,
93319 42991L,42992L,42993L,42994L,42995L,42996L,42997L,42998L,42999L,43000L,
93320 43001L,43002L,43003L,43004L,43005L,43006L,43007L,43008L,43009L,43010L,
93321 43011L,43012L,43013L,43014L,43015L,43016L,43017L,43018L,43019L,43020L,
93322 43021L,43022L,43023L,43024L,43025L,43026L,43027L,43028L,43029L,43030L,
93323 43031L,43032L,43033L,43034L,43035L,43036L,43037L,43038L,43039L,43040L,
93324 43041L,43042L,43043L,43044L,43045L,43046L,43047L,43048L,43049L,43050L,
93325 43051L,43052L,43053L,43054L,43055L,43056L,43057L,43058L,43059L,43060L,
93326 43061L,43062L,43063L,43064L,43065L,43066L,43067L,43068L,43069L,43070L,
93327 43071L,43072L,43073L,43074L,43075L,43076L,43077L,43078L,43079L,43080L,
93328 43081L,43082L,43083L,43084L,43085L,43086L,43087L,43088L,43089L,43090L,
93329 43091L,43092L,43093L,43094L,43095L,43096L,43097L,43098L,43099L,43100L,
93330 43101L,43102L,43103L,43104L,43105L,43106L,43107L,43108L,43109L,43110L,
93331 43111L,43112L,43113L,43114L,43115L,43116L,43117L,43118L,43119L,43120L,
93332 43121L,43122L,43123L,43124L,43125L,43126L,43127L,43128L,43129L,43130L,
93333 43131L,43132L,43133L,43134L,43135L,43136L,43137L,43138L,43139L,43140L,
93334 43141L,43142L,43143L,43144L,43145L,43146L,43147L,43148L,43149L,43150L,
93335 43151L,43152L,43153L,43154L,43155L,43156L,43157L,43158L,43159L,43160L,
93336 43161L,43162L,43163L,43164L,43165L,43166L,43167L,43168L,43169L,43170L,
93337 43171L,43172L,43173L,43174L,43175L,43176L,43177L,43178L,43179L,43180L,
93338 43181L,43182L,43183L,43184L,43185L,43186L,43187L,43188L,43189L,43190L,
93339 43191L,43192L,43193L,43194L,43195L,43196L,43197L,43198L,43199L,43200L,
93340 43201L,43202L,43203L,43204L,43205L,43206L,43207L,43208L,43209L,43210L,
93341 43211L,43212L,43213L,43214L,43215L,43216L,43217L,43218L,43219L,43220L,
93342 43221L,43222L,43223L,43224L,43225L,43226L,43227L,43228L,43229L,43230L,
93343 43231L,43232L,43233L,43234L,43235L,43236L,43237L,43238L,43239L,43240L,
93344 43241L,43242L,43243L,43244L,43245L,43246L,43247L,43248L,43249L,43250L,
93345 43251L,43252L,43253L,43254L,43255L,43256L,43257L,43258L,43259L,43260L,
93346 43261L,43262L,43263L,43264L,43265L,43266L,43267L,43268L,43269L,43270L,
93347 43271L,43272L,43273L,43274L,43275L,43276L,43277L,43278L,43279L,43280L,
93348 43281L,43282L,43283L,43284L,43285L,43286L,43287L,43288L,43289L,43290L,
93349 43291L,43292L,43293L,43294L,43295L,43296L,43297L,43298L,43299L,43300L,
93350 43301L,43302L,43303L,43304L,43305L,43306L,43307L,43308L,43309L,43310L,
93351 43311L,43312L,43313L,43314L,43315L,43316L,43317L,43318L,43319L,43320L,
93352 43321L,43322L,43323L,43324L,43325L,43326L,43327L,43328L,43329L,43330L,
93353 43331L,43332L,43333L,43334L,43335L,43336L,43337L,43338L,43339L,43340L,
93354 43341L,43342L,43343L,43344L,43345L,43346L,43347L,43348L,43349L,43350L,
93355 43351L,43352L,43353L,43354L,43355L,43356L,43357L,43358L,43359L,43360L,
93356 43361L,43362L,43363L,43364L,43365L,43366L,43367L,43368L,43369L,43370L,
93357 43371L,43372L,43373L,43374L,43375L,43376L,43377L,43378L,43379L,43380L,
93358 43381L,43382L,43383L,43384L,43385L,43386L,43387L,43388L,43389L,43390L,
93359 43391L,43392L,43393L,43394L,43395L,43396L,43397L,43398L,43399L,43400L,
93360 43401L,43402L,43403L,43404L,43405L,43406L,43407L,43408L,43409L,43410L,
93361 43411L,43412L,43413L,43414L,43415L,43416L,43417L,43418L,43419L,43420L,
93362 43421L,43422L,43423L,43424L,43425L,43426L,43427L,43428L,43429L,43430L,
93363 43431L,43432L,43433L,43434L,43435L,43436L,43437L,43438L,43439L,43440L,
93364 43441L,43442L,43443L,43444L,43445L,43446L,43447L,43448L,43449L,43450L,
93365 43451L,43452L,43453L,43454L,43455L,43456L,43457L,43458L,43459L,43460L,
93366 43461L,43462L,43463L,43464L,43465L,43466L,43467L,43468L,43469L,43470L,
93367 43471L,43472L,43473L,43474L,43475L,43476L,43477L,43478L,43479L,43480L,
93368 43481L,43482L,43483L,43484L,43485L,43486L,43487L,43488L,43489L,43490L,
93369 43491L,43492L,43493L,43494L,43495L,43496L,43497L,43498L,43499L,43500L,
93370 43501L,43502L,43503L,43504L,43505L,43506L,43507L,43508L,43509L,43510L,
93371 43511L,43512L,43513L,43514L,43515L,43516L,43517L,43518L,43519L,43520L,
93372 43521L,43522L,43523L,43524L,43525L,43526L,43527L,43528L,43529L,43530L,
93373 43531L,43532L,43533L,43534L,43535L,43536L,43537L,43538L,43539L,43540L,
93374 43541L,43542L,43543L,43544L,43545L,43546L,43547L,43548L,43549L,43550L,
93375 43551L,43552L,43553L,43554L,43555L,43556L,43557L,43558L,43559L,43560L,
93376 43561L,43562L,43563L,43564L,43565L,43566L,43567L,43568L,43569L,43570L,
93377 43571L,43572L,43573L,43574L,43575L,43576L,43577L,43578L,43579L,43580L,
93378 43581L,43582L,43583L,43584L,43585L,43586L,43587L,43588L,43589L,43590L,
93379 43591L,43592L,43593L,43594L,43595L,43596L,43597L,43598L,43599L,43600L,
93380 43601L,43602L,43603L,43604L,43605L,43606L,43607L,43608L,43609L,43610L,
93381 43611L,43612L,43613L,43614L,43615L,43616L,43617L,43618L,43619L,43620L,
93382 43621L,43622L,43623L,43624L,43625L,43626L,43627L,43628L,43629L,43630L,
93383 43631L,43632L,43633L,43634L,43635L,43636L,43637L,43638L,43639L,43640L,
93384 43641L,43642L,43643L,43644L,43645L,43646L,43647L,43648L,43649L,43650L,
93385 43651L,43652L,43653L,43654L,43655L,43656L,43657L,43658L,43659L,43660L,
93386 43661L,43662L,43663L,43664L,43665L,43666L,43667L,43668L,43669L,43670L,
93387 43671L,43672L,43673L,43674L,43675L,43676L,43677L,43678L,43679L,43680L,
93388 43681L,43682L,43683L,43684L,43685L,43686L,43687L,43688L,43689L,43690L,
93389 43691L,43692L,43693L,43694L,43695L,43696L,43697L,43698L,43699L,43700L,
93390 43701L,43702L,43703L,43704L,43705L,43706L,43707L,43708L,43709L,43710L,
93391 43711L,43712L,43713L,43714L,43715L,43716L,43717L,43718L,43719L,43720L,
93392 43721L,43722L,43723L,43724L,43725L,43726L,43727L,43728L,43729L,43730L,
93393 43731L,43732L,43733L,43734L,43735L,43736L,43737L,43738L,43739L,43740L,
93394 43741L,43742L,43743L,43744L,43745L,43746L,43747L,43748L,43749L,43750L,
93395 43751L,43752L,43753L,43754L,43755L,43756L,43757L,43758L,43759L,43760L,
93396 43761L,43762L,43763L,43764L,43765L,43766L,43767L,43768L,43769L,43770L,
93397 43771L,43772L,43773L,43774L,43775L,43776L,43777L,43778L,43779L,43780L,
93398 43781L,43782L,43783L,43784L,43785L,43786L,43787L,43788L,43789L,43790L,
93399 43791L,43792L,43793L,43794L,43795L,43796L,43797L,43798L,43799L,43800L,
93400 43801L,43802L,43803L,43804L,43805L,43806L,43807L,43808L,43809L,43810L,
93401 43811L,43812L,43813L,43814L,43815L,43816L,43817L,43818L,43819L,43820L,
93402 43821L,43822L,43823L,43824L,43825L,43826L,43827L,43828L,43829L,43830L,
93403 43831L,43832L,43833L,43834L,43835L,43836L,43837L,43838L,43839L,43840L,
93404 43841L,43842L,43843L,43844L,43845L,43846L,43847L,43848L,43849L,43850L,
93405 43851L,43852L,43853L,43854L,43855L,43856L,43857L,43858L,42931L,43860L,
93406 43861L,43862L,43863L,43864L,43865L,43866L,43867L,43868L,43869L,43870L,
93407 43871L,43872L,43873L,43874L,43875L,43876L,43877L,43878L,43879L,43880L,
93408 43881L,43882L,43883L,43884L,43885L,43886L,43887L,5024,5025,5026,5027,5028,
93409 5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,
93410 5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,
93411 5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,
93412 5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,
93413 5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103,
93414 43968L,43969L,43970L,43971L,43972L,43973L,43974L,43975L,43976L,43977L,
93415 43978L,43979L,43980L,43981L,43982L,43983L,43984L,43985L,43986L,43987L,
93416 43988L,43989L,43990L,43991L,43992L,43993L,43994L,43995L,43996L,43997L,
93417 43998L,43999L,44000L,44001L,44002L,44003L,44004L,44005L,44006L,44007L,
93418 44008L,44009L,44010L,44011L,44012L,44013L,44014L,44015L,44016L,44017L,
93419 44018L,44019L,44020L,44021L,44022L,44023L,44024L,44025L,44026L,44027L,
93420 44028L,44029L,44030L,44031L,44032L,44033L,44034L,44035L,44036L,44037L,
93421 44038L,44039L,44040L,44041L,44042L,44043L,44044L,44045L,44046L,44047L,
93422 44048L,44049L,44050L,44051L,44052L,44053L,44054L,44055L,44056L,44057L,
93423 44058L,44059L,44060L,44061L,44062L,44063L,44064L,44065L,44066L,44067L,
93424 44068L,44069L,44070L,44071L,44072L,44073L,44074L,44075L,44076L,44077L,
93425 44078L,44079L,44080L,44081L,44082L,44083L,44084L,44085L,44086L,44087L,
93426 44088L,44089L,44090L,44091L,44092L,44093L,44094L,44095L,44096L,44097L,
93427 44098L,44099L,44100L,44101L,44102L,44103L,44104L,44105L,44106L,44107L,
93428 44108L,44109L,44110L,44111L,44112L,44113L,44114L,44115L,44116L,44117L,
93429 44118L,44119L,44120L,44121L,44122L,44123L,44124L,44125L,44126L,44127L,
93430 44128L,44129L,44130L,44131L,44132L,44133L,44134L,44135L,44136L,44137L,
93431 44138L,44139L,44140L,44141L,44142L,44143L,44144L,44145L,44146L,44147L,
93432 44148L,44149L,44150L,44151L,44152L,44153L,44154L,44155L,44156L,44157L,
93433 44158L,44159L,44160L,44161L,44162L,44163L,44164L,44165L,44166L,44167L,
93434 44168L,44169L,44170L,44171L,44172L,44173L,44174L,44175L,44176L,44177L,
93435 44178L,44179L,44180L,44181L,44182L,44183L,44184L,44185L,44186L,44187L,
93436 44188L,44189L,44190L,44191L,44192L,44193L,44194L,44195L,44196L,44197L,
93437 44198L,44199L,44200L,44201L,44202L,44203L,44204L,44205L,44206L,44207L,
93438 44208L,44209L,44210L,44211L,44212L,44213L,44214L,44215L,44216L,44217L,
93439 44218L,44219L,44220L,44221L,44222L,44223L,44224L,44225L,44226L,44227L,
93440 44228L,44229L,44230L,44231L,44232L,44233L,44234L,44235L,44236L,44237L,
93441 44238L,44239L,44240L,44241L,44242L,44243L,44244L,44245L,44246L,44247L,
93442 44248L,44249L,44250L,44251L,44252L,44253L,44254L,44255L,44256L,44257L,
93443 44258L,44259L,44260L,44261L,44262L,44263L,44264L,44265L,44266L,44267L,
93444 44268L,44269L,44270L,44271L,44272L,44273L,44274L,44275L,44276L,44277L,
93445 44278L,44279L,44280L,44281L,44282L,44283L,44284L,44285L,44286L,44287L,
93446 44288L,44289L,44290L,44291L,44292L,44293L,44294L,44295L,44296L,44297L,
93447 44298L,44299L,44300L,44301L,44302L,44303L,44304L,44305L,44306L,44307L,
93448 44308L,44309L,44310L,44311L,44312L,44313L,44314L,44315L,44316L,44317L,
93449 44318L,44319L,44320L,44321L,44322L,44323L,44324L,44325L,44326L,44327L,
93450 44328L,44329L,44330L,44331L,44332L,44333L,44334L,44335L,44336L,44337L,
93451 44338L,44339L,44340L,44341L,44342L,44343L,44344L,44345L,44346L,44347L,
93452 44348L,44349L,44350L,44351L,44352L,44353L,44354L,44355L,44356L,44357L,
93453 44358L,44359L,44360L,44361L,44362L,44363L,44364L,44365L,44366L,44367L,
93454 44368L,44369L,44370L,44371L,44372L,44373L,44374L,44375L,44376L,44377L,
93455 44378L,44379L,44380L,44381L,44382L,44383L,44384L,44385L,44386L,44387L,
93456 44388L,44389L,44390L,44391L,44392L,44393L,44394L,44395L,44396L,44397L,
93457 44398L,44399L,44400L,44401L,44402L,44403L,44404L,44405L,44406L,44407L,
93458 44408L,44409L,44410L,44411L,44412L,44413L,44414L,44415L,44416L,44417L,
93459 44418L,44419L,44420L,44421L,44422L,44423L,44424L,44425L,44426L,44427L,
93460 44428L,44429L,44430L,44431L,44432L,44433L,44434L,44435L,44436L,44437L,
93461 44438L,44439L,44440L,44441L,44442L,44443L,44444L,44445L,44446L,44447L,
93462 44448L,44449L,44450L,44451L,44452L,44453L,44454L,44455L,44456L,44457L,
93463 44458L,44459L,44460L,44461L,44462L,44463L,44464L,44465L,44466L,44467L,
93464 44468L,44469L,44470L,44471L,44472L,44473L,44474L,44475L,44476L,44477L,
93465 44478L,44479L,44480L,44481L,44482L,44483L,44484L,44485L,44486L,44487L,
93466 44488L,44489L,44490L,44491L,44492L,44493L,44494L,44495L,44496L,44497L,
93467 44498L,44499L,44500L,44501L,44502L,44503L,44504L,44505L,44506L,44507L,
93468 44508L,44509L,44510L,44511L,44512L,44513L,44514L,44515L,44516L,44517L,
93469 44518L,44519L,44520L,44521L,44522L,44523L,44524L,44525L,44526L,44527L,
93470 44528L,44529L,44530L,44531L,44532L,44533L,44534L,44535L,44536L,44537L,
93471 44538L,44539L,44540L,44541L,44542L,44543L,44544L,44545L,44546L,44547L,
93472 44548L,44549L,44550L,44551L,44552L,44553L,44554L,44555L,44556L,44557L,
93473 44558L,44559L,44560L,44561L,44562L,44563L,44564L,44565L,44566L,44567L,
93474 44568L,44569L,44570L,44571L,44572L,44573L,44574L,44575L,44576L,44577L,
93475 44578L,44579L,44580L,44581L,44582L,44583L,44584L,44585L,44586L,44587L,
93476 44588L,44589L,44590L,44591L,44592L,44593L,44594L,44595L,44596L,44597L,
93477 44598L,44599L,44600L,44601L,44602L,44603L,44604L,44605L,44606L,44607L,
93478 44608L,44609L,44610L,44611L,44612L,44613L,44614L,44615L,44616L,44617L,
93479 44618L,44619L,44620L,44621L,44622L,44623L,44624L,44625L,44626L,44627L,
93480 44628L,44629L,44630L,44631L,44632L,44633L,44634L,44635L,44636L,44637L,
93481 44638L,44639L,44640L,44641L,44642L,44643L,44644L,44645L,44646L,44647L,
93482 44648L,44649L,44650L,44651L,44652L,44653L,44654L,44655L,44656L,44657L,
93483 44658L,44659L,44660L,44661L,44662L,44663L,44664L,44665L,44666L,44667L,
93484 44668L,44669L,44670L,44671L,44672L,44673L,44674L,44675L,44676L,44677L,
93485 44678L,44679L,44680L,44681L,44682L,44683L,44684L,44685L,44686L,44687L,
93486 44688L,44689L,44690L,44691L,44692L,44693L,44694L,44695L,44696L,44697L,
93487 44698L,44699L,44700L,44701L,44702L,44703L,44704L,44705L,44706L,44707L,
93488 44708L,44709L,44710L,44711L,44712L,44713L,44714L,44715L,44716L,44717L,
93489 44718L,44719L,44720L,44721L,44722L,44723L,44724L,44725L,44726L,44727L,
93490 44728L,44729L,44730L,44731L,44732L,44733L,44734L,44735L,44736L,44737L,
93491 44738L,44739L,44740L,44741L,44742L,44743L,44744L,44745L,44746L,44747L,
93492 44748L,44749L,44750L,44751L,44752L,44753L,44754L,44755L,44756L,44757L,
93493 44758L,44759L,44760L,44761L,44762L,44763L,44764L,44765L,44766L,44767L,
93494 44768L,44769L,44770L,44771L,44772L,44773L,44774L,44775L,44776L,44777L,
93495 44778L,44779L,44780L,44781L,44782L,44783L,44784L,44785L,44786L,44787L,
93496 44788L,44789L,44790L,44791L,44792L,44793L,44794L,44795L,44796L,44797L,
93497 44798L,44799L,44800L,44801L,44802L,44803L,44804L,44805L,44806L,44807L,
93498 44808L,44809L,44810L,44811L,44812L,44813L,44814L,44815L,44816L,44817L,
93499 44818L,44819L,44820L,44821L,44822L,44823L,44824L,44825L,44826L,44827L,
93500 44828L,44829L,44830L,44831L,44832L,44833L,44834L,44835L,44836L,44837L,
93501 44838L,44839L,44840L,44841L,44842L,44843L,44844L,44845L,44846L,44847L,
93502 44848L,44849L,44850L,44851L,44852L,44853L,44854L,44855L,44856L,44857L,
93503 44858L,44859L,44860L,44861L,44862L,44863L,44864L,44865L,44866L,44867L,
93504 44868L,44869L,44870L,44871L,44872L,44873L,44874L,44875L,44876L,44877L,
93505 44878L,44879L,44880L,44881L,44882L,44883L,44884L,44885L,44886L,44887L,
93506 44888L,44889L,44890L,44891L,44892L,44893L,44894L,44895L,44896L,44897L,
93507 44898L,44899L,44900L,44901L,44902L,44903L,44904L,44905L,44906L,44907L,
93508 44908L,44909L,44910L,44911L,44912L,44913L,44914L,44915L,44916L,44917L,
93509 44918L,44919L,44920L,44921L,44922L,44923L,44924L,44925L,44926L,44927L,
93510 44928L,44929L,44930L,44931L,44932L,44933L,44934L,44935L,44936L,44937L,
93511 44938L,44939L,44940L,44941L,44942L,44943L,44944L,44945L,44946L,44947L,
93512 44948L,44949L,44950L,44951L,44952L,44953L,44954L,44955L,44956L,44957L,
93513 44958L,44959L,44960L,44961L,44962L,44963L,44964L,44965L,44966L,44967L,
93514 44968L,44969L,44970L,44971L,44972L,44973L,44974L,44975L,44976L,44977L,
93515 44978L,44979L,44980L,44981L,44982L,44983L,44984L,44985L,44986L,44987L,
93516 44988L,44989L,44990L,44991L,44992L,44993L,44994L,44995L,44996L,44997L,
93517 44998L,44999L,45000L,45001L,45002L,45003L,45004L,45005L,45006L,45007L,
93518 45008L,45009L,45010L,45011L,45012L,45013L,45014L,45015L,45016L,45017L,
93519 45018L,45019L,45020L,45021L,45022L,45023L,45024L,45025L,45026L,45027L,
93520 45028L,45029L,45030L,45031L,45032L,45033L,45034L,45035L,45036L,45037L,
93521 45038L,45039L,45040L,45041L,45042L,45043L,45044L,45045L,45046L,45047L,
93522 45048L,45049L,45050L,45051L,45052L,45053L,45054L,45055L,45056L,45057L,
93523 45058L,45059L,45060L,45061L,45062L,45063L,45064L,45065L,45066L,45067L,
93524 45068L,45069L,45070L,45071L,45072L,45073L,45074L,45075L,45076L,45077L,
93525 45078L,45079L,45080L,45081L,45082L,45083L,45084L,45085L,45086L,45087L,
93526 45088L,45089L,45090L,45091L,45092L,45093L,45094L,45095L,45096L,45097L,
93527 45098L,45099L,45100L,45101L,45102L,45103L,45104L,45105L,45106L,45107L,
93528 45108L,45109L,45110L,45111L,45112L,45113L,45114L,45115L,45116L,45117L,
93529 45118L,45119L,45120L,45121L,45122L,45123L,45124L,45125L,45126L,45127L,
93530 45128L,45129L,45130L,45131L,45132L,45133L,45134L,45135L,45136L,45137L,
93531 45138L,45139L,45140L,45141L,45142L,45143L,45144L,45145L,45146L,45147L,
93532 45148L,45149L,45150L,45151L,45152L,45153L,45154L,45155L,45156L,45157L,
93533 45158L,45159L,45160L,45161L,45162L,45163L,45164L,45165L,45166L,45167L,
93534 45168L,45169L,45170L,45171L,45172L,45173L,45174L,45175L,45176L,45177L,
93535 45178L,45179L,45180L,45181L,45182L,45183L,45184L,45185L,45186L,45187L,
93536 45188L,45189L,45190L,45191L,45192L,45193L,45194L,45195L,45196L,45197L,
93537 45198L,45199L,45200L,45201L,45202L,45203L,45204L,45205L,45206L,45207L,
93538 45208L,45209L,45210L,45211L,45212L,45213L,45214L,45215L,45216L,45217L,
93539 45218L,45219L,45220L,45221L,45222L,45223L,45224L,45225L,45226L,45227L,
93540 45228L,45229L,45230L,45231L,45232L,45233L,45234L,45235L,45236L,45237L,
93541 45238L,45239L,45240L,45241L,45242L,45243L,45244L,45245L,45246L,45247L,
93542 45248L,45249L,45250L,45251L,45252L,45253L,45254L,45255L,45256L,45257L,
93543 45258L,45259L,45260L,45261L,45262L,45263L,45264L,45265L,45266L,45267L,
93544 45268L,45269L,45270L,45271L,45272L,45273L,45274L,45275L,45276L,45277L,
93545 45278L,45279L,45280L,45281L,45282L,45283L,45284L,45285L,45286L,45287L,
93546 45288L,45289L,45290L,45291L,45292L,45293L,45294L,45295L,45296L,45297L,
93547 45298L,45299L,45300L,45301L,45302L,45303L,45304L,45305L,45306L,45307L,
93548 45308L,45309L,45310L,45311L,45312L,45313L,45314L,45315L,45316L,45317L,
93549 45318L,45319L,45320L,45321L,45322L,45323L,45324L,45325L,45326L,45327L,
93550 45328L,45329L,45330L,45331L,45332L,45333L,45334L,45335L,45336L,45337L,
93551 45338L,45339L,45340L,45341L,45342L,45343L,45344L,45345L,45346L,45347L,
93552 45348L,45349L,45350L,45351L,45352L,45353L,45354L,45355L,45356L,45357L,
93553 45358L,45359L,45360L,45361L,45362L,45363L,45364L,45365L,45366L,45367L,
93554 45368L,45369L,45370L,45371L,45372L,45373L,45374L,45375L,45376L,45377L,
93555 45378L,45379L,45380L,45381L,45382L,45383L,45384L,45385L,45386L,45387L,
93556 45388L,45389L,45390L,45391L,45392L,45393L,45394L,45395L,45396L,45397L,
93557 45398L,45399L,45400L,45401L,45402L,45403L,45404L,45405L,45406L,45407L,
93558 45408L,45409L,45410L,45411L,45412L,45413L,45414L,45415L,45416L,45417L,
93559 45418L,45419L,45420L,45421L,45422L,45423L,45424L,45425L,45426L,45427L,
93560 45428L,45429L,45430L,45431L,45432L,45433L,45434L,45435L,45436L,45437L,
93561 45438L,45439L,45440L,45441L,45442L,45443L,45444L,45445L,45446L,45447L,
93562 45448L,45449L,45450L,45451L,45452L,45453L,45454L,45455L,45456L,45457L,
93563 45458L,45459L,45460L,45461L,45462L,45463L,45464L,45465L,45466L,45467L,
93564 45468L,45469L,45470L,45471L,45472L,45473L,45474L,45475L,45476L,45477L,
93565 45478L,45479L,45480L,45481L,45482L,45483L,45484L,45485L,45486L,45487L,
93566 45488L,45489L,45490L,45491L,45492L,45493L,45494L,45495L,45496L,45497L,
93567 45498L,45499L,45500L,45501L,45502L,45503L,45504L,45505L,45506L,45507L,
93568 45508L,45509L,45510L,45511L,45512L,45513L,45514L,45515L,45516L,45517L,
93569 45518L,45519L,45520L,45521L,45522L,45523L,45524L,45525L,45526L,45527L,
93570 45528L,45529L,45530L,45531L,45532L,45533L,45534L,45535L,45536L,45537L,
93571 45538L,45539L,45540L,45541L,45542L,45543L,45544L,45545L,45546L,45547L,
93572 45548L,45549L,45550L,45551L,45552L,45553L,45554L,45555L,45556L,45557L,
93573 45558L,45559L,45560L,45561L,45562L,45563L,45564L,45565L,45566L,45567L,
93574 45568L,45569L,45570L,45571L,45572L,45573L,45574L,45575L,45576L,45577L,
93575 45578L,45579L,45580L,45581L,45582L,45583L,45584L,45585L,45586L,45587L,
93576 45588L,45589L,45590L,45591L,45592L,45593L,45594L,45595L,45596L,45597L,
93577 45598L,45599L,45600L,45601L,45602L,45603L,45604L,45605L,45606L,45607L,
93578 45608L,45609L,45610L,45611L,45612L,45613L,45614L,45615L,45616L,45617L,
93579 45618L,45619L,45620L,45621L,45622L,45623L,45624L,45625L,45626L,45627L,
93580 45628L,45629L,45630L,45631L,45632L,45633L,45634L,45635L,45636L,45637L,
93581 45638L,45639L,45640L,45641L,45642L,45643L,45644L,45645L,45646L,45647L,
93582 45648L,45649L,45650L,45651L,45652L,45653L,45654L,45655L,45656L,45657L,
93583 45658L,45659L,45660L,45661L,45662L,45663L,45664L,45665L,45666L,45667L,
93584 45668L,45669L,45670L,45671L,45672L,45673L,45674L,45675L,45676L,45677L,
93585 45678L,45679L,45680L,45681L,45682L,45683L,45684L,45685L,45686L,45687L,
93586 45688L,45689L,45690L,45691L,45692L,45693L,45694L,45695L,45696L,45697L,
93587 45698L,45699L,45700L,45701L,45702L,45703L,45704L,45705L,45706L,45707L,
93588 45708L,45709L,45710L,45711L,45712L,45713L,45714L,45715L,45716L,45717L,
93589 45718L,45719L,45720L,45721L,45722L,45723L,45724L,45725L,45726L,45727L,
93590 45728L,45729L,45730L,45731L,45732L,45733L,45734L,45735L,45736L,45737L,
93591 45738L,45739L,45740L,45741L,45742L,45743L,45744L,45745L,45746L,45747L,
93592 45748L,45749L,45750L,45751L,45752L,45753L,45754L,45755L,45756L,45757L,
93593 45758L,45759L,45760L,45761L,45762L,45763L,45764L,45765L,45766L,45767L,
93594 45768L,45769L,45770L,45771L,45772L,45773L,45774L,45775L,45776L,45777L,
93595 45778L,45779L,45780L,45781L,45782L,45783L,45784L,45785L,45786L,45787L,
93596 45788L,45789L,45790L,45791L,45792L,45793L,45794L,45795L,45796L,45797L,
93597 45798L,45799L,45800L,45801L,45802L,45803L,45804L,45805L,45806L,45807L,
93598 45808L,45809L,45810L,45811L,45812L,45813L,45814L,45815L,45816L,45817L,
93599 45818L,45819L,45820L,45821L,45822L,45823L,45824L,45825L,45826L,45827L,
93600 45828L,45829L,45830L,45831L,45832L,45833L,45834L,45835L,45836L,45837L,
93601 45838L,45839L,45840L,45841L,45842L,45843L,45844L,45845L,45846L,45847L,
93602 45848L,45849L,45850L,45851L,45852L,45853L,45854L,45855L,45856L,45857L,
93603 45858L,45859L,45860L,45861L,45862L,45863L,45864L,45865L,45866L,45867L,
93604 45868L,45869L,45870L,45871L,45872L,45873L,45874L,45875L,45876L,45877L,
93605 45878L,45879L,45880L,45881L,45882L,45883L,45884L,45885L,45886L,45887L,
93606 45888L,45889L,45890L,45891L,45892L,45893L,45894L,45895L,45896L,45897L,
93607 45898L,45899L,45900L,45901L,45902L,45903L,45904L,45905L,45906L,45907L,
93608 45908L,45909L,45910L,45911L,45912L,45913L,45914L,45915L,45916L,45917L,
93609 45918L,45919L,45920L,45921L,45922L,45923L,45924L,45925L,45926L,45927L,
93610 45928L,45929L,45930L,45931L,45932L,45933L,45934L,45935L,45936L,45937L,
93611 45938L,45939L,45940L,45941L,45942L,45943L,45944L,45945L,45946L,45947L,
93612 45948L,45949L,45950L,45951L,45952L,45953L,45954L,45955L,45956L,45957L,
93613 45958L,45959L,45960L,45961L,45962L,45963L,45964L,45965L,45966L,45967L,
93614 45968L,45969L,45970L,45971L,45972L,45973L,45974L,45975L,45976L,45977L,
93615 45978L,45979L,45980L,45981L,45982L,45983L,45984L,45985L,45986L,45987L,
93616 45988L,45989L,45990L,45991L,45992L,45993L,45994L,45995L,45996L,45997L,
93617 45998L,45999L,46000L,46001L,46002L,46003L,46004L,46005L,46006L,46007L,
93618 46008L,46009L,46010L,46011L,46012L,46013L,46014L,46015L,46016L,46017L,
93619 46018L,46019L,46020L,46021L,46022L,46023L,46024L,46025L,46026L,46027L,
93620 46028L,46029L,46030L,46031L,46032L,46033L,46034L,46035L,46036L,46037L,
93621 46038L,46039L,46040L,46041L,46042L,46043L,46044L,46045L,46046L,46047L,
93622 46048L,46049L,46050L,46051L,46052L,46053L,46054L,46055L,46056L,46057L,
93623 46058L,46059L,46060L,46061L,46062L,46063L,46064L,46065L,46066L,46067L,
93624 46068L,46069L,46070L,46071L,46072L,46073L,46074L,46075L,46076L,46077L,
93625 46078L,46079L,46080L,46081L,46082L,46083L,46084L,46085L,46086L,46087L,
93626 46088L,46089L,46090L,46091L,46092L,46093L,46094L,46095L,46096L,46097L,
93627 46098L,46099L,46100L,46101L,46102L,46103L,46104L,46105L,46106L,46107L,
93628 46108L,46109L,46110L,46111L,46112L,46113L,46114L,46115L,46116L,46117L,
93629 46118L,46119L,46120L,46121L,46122L,46123L,46124L,46125L,46126L,46127L,
93630 46128L,46129L,46130L,46131L,46132L,46133L,46134L,46135L,46136L,46137L,
93631 46138L,46139L,46140L,46141L,46142L,46143L,46144L,46145L,46146L,46147L,
93632 46148L,46149L,46150L,46151L,46152L,46153L,46154L,46155L,46156L,46157L,
93633 46158L,46159L,46160L,46161L,46162L,46163L,46164L,46165L,46166L,46167L,
93634 46168L,46169L,46170L,46171L,46172L,46173L,46174L,46175L,46176L,46177L,
93635 46178L,46179L,46180L,46181L,46182L,46183L,46184L,46185L,46186L,46187L,
93636 46188L,46189L,46190L,46191L,46192L,46193L,46194L,46195L,46196L,46197L,
93637 46198L,46199L,46200L,46201L,46202L,46203L,46204L,46205L,46206L,46207L,
93638 46208L,46209L,46210L,46211L,46212L,46213L,46214L,46215L,46216L,46217L,
93639 46218L,46219L,46220L,46221L,46222L,46223L,46224L,46225L,46226L,46227L,
93640 46228L,46229L,46230L,46231L,46232L,46233L,46234L,46235L,46236L,46237L,
93641 46238L,46239L,46240L,46241L,46242L,46243L,46244L,46245L,46246L,46247L,
93642 46248L,46249L,46250L,46251L,46252L,46253L,46254L,46255L,46256L,46257L,
93643 46258L,46259L,46260L,46261L,46262L,46263L,46264L,46265L,46266L,46267L,
93644 46268L,46269L,46270L,46271L,46272L,46273L,46274L,46275L,46276L,46277L,
93645 46278L,46279L,46280L,46281L,46282L,46283L,46284L,46285L,46286L,46287L,
93646 46288L,46289L,46290L,46291L,46292L,46293L,46294L,46295L,46296L,46297L,
93647 46298L,46299L,46300L,46301L,46302L,46303L,46304L,46305L,46306L,46307L,
93648 46308L,46309L,46310L,46311L,46312L,46313L,46314L,46315L,46316L,46317L,
93649 46318L,46319L,46320L,46321L,46322L,46323L,46324L,46325L,46326L,46327L,
93650 46328L,46329L,46330L,46331L,46332L,46333L,46334L,46335L,46336L,46337L,
93651 46338L,46339L,46340L,46341L,46342L,46343L,46344L,46345L,46346L,46347L,
93652 46348L,46349L,46350L,46351L,46352L,46353L,46354L,46355L,46356L,46357L,
93653 46358L,46359L,46360L,46361L,46362L,46363L,46364L,46365L,46366L,46367L,
93654 46368L,46369L,46370L,46371L,46372L,46373L,46374L,46375L,46376L,46377L,
93655 46378L,46379L,46380L,46381L,46382L,46383L,46384L,46385L,46386L,46387L,
93656 46388L,46389L,46390L,46391L,46392L,46393L,46394L,46395L,46396L,46397L,
93657 46398L,46399L,46400L,46401L,46402L,46403L,46404L,46405L,46406L,46407L,
93658 46408L,46409L,46410L,46411L,46412L,46413L,46414L,46415L,46416L,46417L,
93659 46418L,46419L,46420L,46421L,46422L,46423L,46424L,46425L,46426L,46427L,
93660 46428L,46429L,46430L,46431L,46432L,46433L,46434L,46435L,46436L,46437L,
93661 46438L,46439L,46440L,46441L,46442L,46443L,46444L,46445L,46446L,46447L,
93662 46448L,46449L,46450L,46451L,46452L,46453L,46454L,46455L,46456L,46457L,
93663 46458L,46459L,46460L,46461L,46462L,46463L,46464L,46465L,46466L,46467L,
93664 46468L,46469L,46470L,46471L,46472L,46473L,46474L,46475L,46476L,46477L,
93665 46478L,46479L,46480L,46481L,46482L,46483L,46484L,46485L,46486L,46487L,
93666 46488L,46489L,46490L,46491L,46492L,46493L,46494L,46495L,46496L,46497L,
93667 46498L,46499L,46500L,46501L,46502L,46503L,46504L,46505L,46506L,46507L,
93668 46508L,46509L,46510L,46511L,46512L,46513L,46514L,46515L,46516L,46517L,
93669 46518L,46519L,46520L,46521L,46522L,46523L,46524L,46525L,46526L,46527L,
93670 46528L,46529L,46530L,46531L,46532L,46533L,46534L,46535L,46536L,46537L,
93671 46538L,46539L,46540L,46541L,46542L,46543L,46544L,46545L,46546L,46547L,
93672 46548L,46549L,46550L,46551L,46552L,46553L,46554L,46555L,46556L,46557L,
93673 46558L,46559L,46560L,46561L,46562L,46563L,46564L,46565L,46566L,46567L,
93674 46568L,46569L,46570L,46571L,46572L,46573L,46574L,46575L,46576L,46577L,
93675 46578L,46579L,46580L,46581L,46582L,46583L,46584L,46585L,46586L,46587L,
93676 46588L,46589L,46590L,46591L,46592L,46593L,46594L,46595L,46596L,46597L,
93677 46598L,46599L,46600L,46601L,46602L,46603L,46604L,46605L,46606L,46607L,
93678 46608L,46609L,46610L,46611L,46612L,46613L,46614L,46615L,46616L,46617L,
93679 46618L,46619L,46620L,46621L,46622L,46623L,46624L,46625L,46626L,46627L,
93680 46628L,46629L,46630L,46631L,46632L,46633L,46634L,46635L,46636L,46637L,
93681 46638L,46639L,46640L,46641L,46642L,46643L,46644L,46645L,46646L,46647L,
93682 46648L,46649L,46650L,46651L,46652L,46653L,46654L,46655L,46656L,46657L,
93683 46658L,46659L,46660L,46661L,46662L,46663L,46664L,46665L,46666L,46667L,
93684 46668L,46669L,46670L,46671L,46672L,46673L,46674L,46675L,46676L,46677L,
93685 46678L,46679L,46680L,46681L,46682L,46683L,46684L,46685L,46686L,46687L,
93686 46688L,46689L,46690L,46691L,46692L,46693L,46694L,46695L,46696L,46697L,
93687 46698L,46699L,46700L,46701L,46702L,46703L,46704L,46705L,46706L,46707L,
93688 46708L,46709L,46710L,46711L,46712L,46713L,46714L,46715L,46716L,46717L,
93689 46718L,46719L,46720L,46721L,46722L,46723L,46724L,46725L,46726L,46727L,
93690 46728L,46729L,46730L,46731L,46732L,46733L,46734L,46735L,46736L,46737L,
93691 46738L,46739L,46740L,46741L,46742L,46743L,46744L,46745L,46746L,46747L,
93692 46748L,46749L,46750L,46751L,46752L,46753L,46754L,46755L,46756L,46757L,
93693 46758L,46759L,46760L,46761L,46762L,46763L,46764L,46765L,46766L,46767L,
93694 46768L,46769L,46770L,46771L,46772L,46773L,46774L,46775L,46776L,46777L,
93695 46778L,46779L,46780L,46781L,46782L,46783L,46784L,46785L,46786L,46787L,
93696 46788L,46789L,46790L,46791L,46792L,46793L,46794L,46795L,46796L,46797L,
93697 46798L,46799L,46800L,46801L,46802L,46803L,46804L,46805L,46806L,46807L,
93698 46808L,46809L,46810L,46811L,46812L,46813L,46814L,46815L,46816L,46817L,
93699 46818L,46819L,46820L,46821L,46822L,46823L,46824L,46825L,46826L,46827L,
93700 46828L,46829L,46830L,46831L,46832L,46833L,46834L,46835L,46836L,46837L,
93701 46838L,46839L,46840L,46841L,46842L,46843L,46844L,46845L,46846L,46847L,
93702 46848L,46849L,46850L,46851L,46852L,46853L,46854L,46855L,46856L,46857L,
93703 46858L,46859L,46860L,46861L,46862L,46863L,46864L,46865L,46866L,46867L,
93704 46868L,46869L,46870L,46871L,46872L,46873L,46874L,46875L,46876L,46877L,
93705 46878L,46879L,46880L,46881L,46882L,46883L,46884L,46885L,46886L,46887L,
93706 46888L,46889L,46890L,46891L,46892L,46893L,46894L,46895L,46896L,46897L,
93707 46898L,46899L,46900L,46901L,46902L,46903L,46904L,46905L,46906L,46907L,
93708 46908L,46909L,46910L,46911L,46912L,46913L,46914L,46915L,46916L,46917L,
93709 46918L,46919L,46920L,46921L,46922L,46923L,46924L,46925L,46926L,46927L,
93710 46928L,46929L,46930L,46931L,46932L,46933L,46934L,46935L,46936L,46937L,
93711 46938L,46939L,46940L,46941L,46942L,46943L,46944L,46945L,46946L,46947L,
93712 46948L,46949L,46950L,46951L,46952L,46953L,46954L,46955L,46956L,46957L,
93713 46958L,46959L,46960L,46961L,46962L,46963L,46964L,46965L,46966L,46967L,
93714 46968L,46969L,46970L,46971L,46972L,46973L,46974L,46975L,46976L,46977L,
93715 46978L,46979L,46980L,46981L,46982L,46983L,46984L,46985L,46986L,46987L,
93716 46988L,46989L,46990L,46991L,46992L,46993L,46994L,46995L,46996L,46997L,
93717 46998L,46999L,47000L,47001L,47002L,47003L,47004L,47005L,47006L,47007L,
93718 47008L,47009L,47010L,47011L,47012L,47013L,47014L,47015L,47016L,47017L,
93719 47018L,47019L,47020L,47021L,47022L,47023L,47024L,47025L,47026L,47027L,
93720 47028L,47029L,47030L,47031L,47032L,47033L,47034L,47035L,47036L,47037L,
93721 47038L,47039L,47040L,47041L,47042L,47043L,47044L,47045L,47046L,47047L,
93722 47048L,47049L,47050L,47051L,47052L,47053L,47054L,47055L,47056L,47057L,
93723 47058L,47059L,47060L,47061L,47062L,47063L,47064L,47065L,47066L,47067L,
93724 47068L,47069L,47070L,47071L,47072L,47073L,47074L,47075L,47076L,47077L,
93725 47078L,47079L,47080L,47081L,47082L,47083L,47084L,47085L,47086L,47087L,
93726 47088L,47089L,47090L,47091L,47092L,47093L,47094L,47095L,47096L,47097L,
93727 47098L,47099L,47100L,47101L,47102L,47103L,47104L,47105L,47106L,47107L,
93728 47108L,47109L,47110L,47111L,47112L,47113L,47114L,47115L,47116L,47117L,
93729 47118L,47119L,47120L,47121L,47122L,47123L,47124L,47125L,47126L,47127L,
93730 47128L,47129L,47130L,47131L,47132L,47133L,47134L,47135L,47136L,47137L,
93731 47138L,47139L,47140L,47141L,47142L,47143L,47144L,47145L,47146L,47147L,
93732 47148L,47149L,47150L,47151L,47152L,47153L,47154L,47155L,47156L,47157L,
93733 47158L,47159L,47160L,47161L,47162L,47163L,47164L,47165L,47166L,47167L,
93734 47168L,47169L,47170L,47171L,47172L,47173L,47174L,47175L,47176L,47177L,
93735 47178L,47179L,47180L,47181L,47182L,47183L,47184L,47185L,47186L,47187L,
93736 47188L,47189L,47190L,47191L,47192L,47193L,47194L,47195L,47196L,47197L,
93737 47198L,47199L,47200L,47201L,47202L,47203L,47204L,47205L,47206L,47207L,
93738 47208L,47209L,47210L,47211L,47212L,47213L,47214L,47215L,47216L,47217L,
93739 47218L,47219L,47220L,47221L,47222L,47223L,47224L,47225L,47226L,47227L,
93740 47228L,47229L,47230L,47231L,47232L,47233L,47234L,47235L,47236L,47237L,
93741 47238L,47239L,47240L,47241L,47242L,47243L,47244L,47245L,47246L,47247L,
93742 47248L,47249L,47250L,47251L,47252L,47253L,47254L,47255L,47256L,47257L,
93743 47258L,47259L,47260L,47261L,47262L,47263L,47264L,47265L,47266L,47267L,
93744 47268L,47269L,47270L,47271L,47272L,47273L,47274L,47275L,47276L,47277L,
93745 47278L,47279L,47280L,47281L,47282L,47283L,47284L,47285L,47286L,47287L,
93746 47288L,47289L,47290L,47291L,47292L,47293L,47294L,47295L,47296L,47297L,
93747 47298L,47299L,47300L,47301L,47302L,47303L,47304L,47305L,47306L,47307L,
93748 47308L,47309L,47310L,47311L,47312L,47313L,47314L,47315L,47316L,47317L,
93749 47318L,47319L,47320L,47321L,47322L,47323L,47324L,47325L,47326L,47327L,
93750 47328L,47329L,47330L,47331L,47332L,47333L,47334L,47335L,47336L,47337L,
93751 47338L,47339L,47340L,47341L,47342L,47343L,47344L,47345L,47346L,47347L,
93752 47348L,47349L,47350L,47351L,47352L,47353L,47354L,47355L,47356L,47357L,
93753 47358L,47359L,47360L,47361L,47362L,47363L,47364L,47365L,47366L,47367L,
93754 47368L,47369L,47370L,47371L,47372L,47373L,47374L,47375L,47376L,47377L,
93755 47378L,47379L,47380L,47381L,47382L,47383L,47384L,47385L,47386L,47387L,
93756 47388L,47389L,47390L,47391L,47392L,47393L,47394L,47395L,47396L,47397L,
93757 47398L,47399L,47400L,47401L,47402L,47403L,47404L,47405L,47406L,47407L,
93758 47408L,47409L,47410L,47411L,47412L,47413L,47414L,47415L,47416L,47417L,
93759 47418L,47419L,47420L,47421L,47422L,47423L,47424L,47425L,47426L,47427L,
93760 47428L,47429L,47430L,47431L,47432L,47433L,47434L,47435L,47436L,47437L,
93761 47438L,47439L,47440L,47441L,47442L,47443L,47444L,47445L,47446L,47447L,
93762 47448L,47449L,47450L,47451L,47452L,47453L,47454L,47455L,47456L,47457L,
93763 47458L,47459L,47460L,47461L,47462L,47463L,47464L,47465L,47466L,47467L,
93764 47468L,47469L,47470L,47471L,47472L,47473L,47474L,47475L,47476L,47477L,
93765 47478L,47479L,47480L,47481L,47482L,47483L,47484L,47485L,47486L,47487L,
93766 47488L,47489L,47490L,47491L,47492L,47493L,47494L,47495L,47496L,47497L,
93767 47498L,47499L,47500L,47501L,47502L,47503L,47504L,47505L,47506L,47507L,
93768 47508L,47509L,47510L,47511L,47512L,47513L,47514L,47515L,47516L,47517L,
93769 47518L,47519L,47520L,47521L,47522L,47523L,47524L,47525L,47526L,47527L,
93770 47528L,47529L,47530L,47531L,47532L,47533L,47534L,47535L,47536L,47537L,
93771 47538L,47539L,47540L,47541L,47542L,47543L,47544L,47545L,47546L,47547L,
93772 47548L,47549L,47550L,47551L,47552L,47553L,47554L,47555L,47556L,47557L,
93773 47558L,47559L,47560L,47561L,47562L,47563L,47564L,47565L,47566L,47567L,
93774 47568L,47569L,47570L,47571L,47572L,47573L,47574L,47575L,47576L,47577L,
93775 47578L,47579L,47580L,47581L,47582L,47583L,47584L,47585L,47586L,47587L,
93776 47588L,47589L,47590L,47591L,47592L,47593L,47594L,47595L,47596L,47597L,
93777 47598L,47599L,47600L,47601L,47602L,47603L,47604L,47605L,47606L,47607L,
93778 47608L,47609L,47610L,47611L,47612L,47613L,47614L,47615L,47616L,47617L,
93779 47618L,47619L,47620L,47621L,47622L,47623L,47624L,47625L,47626L,47627L,
93780 47628L,47629L,47630L,47631L,47632L,47633L,47634L,47635L,47636L,47637L,
93781 47638L,47639L,47640L,47641L,47642L,47643L,47644L,47645L,47646L,47647L,
93782 47648L,47649L,47650L,47651L,47652L,47653L,47654L,47655L,47656L,47657L,
93783 47658L,47659L,47660L,47661L,47662L,47663L,47664L,47665L,47666L,47667L,
93784 47668L,47669L,47670L,47671L,47672L,47673L,47674L,47675L,47676L,47677L,
93785 47678L,47679L,47680L,47681L,47682L,47683L,47684L,47685L,47686L,47687L,
93786 47688L,47689L,47690L,47691L,47692L,47693L,47694L,47695L,47696L,47697L,
93787 47698L,47699L,47700L,47701L,47702L,47703L,47704L,47705L,47706L,47707L,
93788 47708L,47709L,47710L,47711L,47712L,47713L,47714L,47715L,47716L,47717L,
93789 47718L,47719L,47720L,47721L,47722L,47723L,47724L,47725L,47726L,47727L,
93790 47728L,47729L,47730L,47731L,47732L,47733L,47734L,47735L,47736L,47737L,
93791 47738L,47739L,47740L,47741L,47742L,47743L,47744L,47745L,47746L,47747L,
93792 47748L,47749L,47750L,47751L,47752L,47753L,47754L,47755L,47756L,47757L,
93793 47758L,47759L,47760L,47761L,47762L,47763L,47764L,47765L,47766L,47767L,
93794 47768L,47769L,47770L,47771L,47772L,47773L,47774L,47775L,47776L,47777L,
93795 47778L,47779L,47780L,47781L,47782L,47783L,47784L,47785L,47786L,47787L,
93796 47788L,47789L,47790L,47791L,47792L,47793L,47794L,47795L,47796L,47797L,
93797 47798L,47799L,47800L,47801L,47802L,47803L,47804L,47805L,47806L,47807L,
93798 47808L,47809L,47810L,47811L,47812L,47813L,47814L,47815L,47816L,47817L,
93799 47818L,47819L,47820L,47821L,47822L,47823L,47824L,47825L,47826L,47827L,
93800 47828L,47829L,47830L,47831L,47832L,47833L,47834L,47835L,47836L,47837L,
93801 47838L,47839L,47840L,47841L,47842L,47843L,47844L,47845L,47846L,47847L,
93802 47848L,47849L,47850L,47851L,47852L,47853L,47854L,47855L,47856L,47857L,
93803 47858L,47859L,47860L,47861L,47862L,47863L,47864L,47865L,47866L,47867L,
93804 47868L,47869L,47870L,47871L,47872L,47873L,47874L,47875L,47876L,47877L,
93805 47878L,47879L,47880L,47881L,47882L,47883L,47884L,47885L,47886L,47887L,
93806 47888L,47889L,47890L,47891L,47892L,47893L,47894L,47895L,47896L,47897L,
93807 47898L,47899L,47900L,47901L,47902L,47903L,47904L,47905L,47906L,47907L,
93808 47908L,47909L,47910L,47911L,47912L,47913L,47914L,47915L,47916L,47917L,
93809 47918L,47919L,47920L,47921L,47922L,47923L,47924L,47925L,47926L,47927L,
93810 47928L,47929L,47930L,47931L,47932L,47933L,47934L,47935L,47936L,47937L,
93811 47938L,47939L,47940L,47941L,47942L,47943L,47944L,47945L,47946L,47947L,
93812 47948L,47949L,47950L,47951L,47952L,47953L,47954L,47955L,47956L,47957L,
93813 47958L,47959L,47960L,47961L,47962L,47963L,47964L,47965L,47966L,47967L,
93814 47968L,47969L,47970L,47971L,47972L,47973L,47974L,47975L,47976L,47977L,
93815 47978L,47979L,47980L,47981L,47982L,47983L,47984L,47985L,47986L,47987L,
93816 47988L,47989L,47990L,47991L,47992L,47993L,47994L,47995L,47996L,47997L,
93817 47998L,47999L,48000L,48001L,48002L,48003L,48004L,48005L,48006L,48007L,
93818 48008L,48009L,48010L,48011L,48012L,48013L,48014L,48015L,48016L,48017L,
93819 48018L,48019L,48020L,48021L,48022L,48023L,48024L,48025L,48026L,48027L,
93820 48028L,48029L,48030L,48031L,48032L,48033L,48034L,48035L,48036L,48037L,
93821 48038L,48039L,48040L,48041L,48042L,48043L,48044L,48045L,48046L,48047L,
93822 48048L,48049L,48050L,48051L,48052L,48053L,48054L,48055L,48056L,48057L,
93823 48058L,48059L,48060L,48061L,48062L,48063L,48064L,48065L,48066L,48067L,
93824 48068L,48069L,48070L,48071L,48072L,48073L,48074L,48075L,48076L,48077L,
93825 48078L,48079L,48080L,48081L,48082L,48083L,48084L,48085L,48086L,48087L,
93826 48088L,48089L,48090L,48091L,48092L,48093L,48094L,48095L,48096L,48097L,
93827 48098L,48099L,48100L,48101L,48102L,48103L,48104L,48105L,48106L,48107L,
93828 48108L,48109L,48110L,48111L,48112L,48113L,48114L,48115L,48116L,48117L,
93829 48118L,48119L,48120L,48121L,48122L,48123L,48124L,48125L,48126L,48127L,
93830 48128L,48129L,48130L,48131L,48132L,48133L,48134L,48135L,48136L,48137L,
93831 48138L,48139L,48140L,48141L,48142L,48143L,48144L,48145L,48146L,48147L,
93832 48148L,48149L,48150L,48151L,48152L,48153L,48154L,48155L,48156L,48157L,
93833 48158L,48159L,48160L,48161L,48162L,48163L,48164L,48165L,48166L,48167L,
93834 48168L,48169L,48170L,48171L,48172L,48173L,48174L,48175L,48176L,48177L,
93835 48178L,48179L,48180L,48181L,48182L,48183L,48184L,48185L,48186L,48187L,
93836 48188L,48189L,48190L,48191L,48192L,48193L,48194L,48195L,48196L,48197L,
93837 48198L,48199L,48200L,48201L,48202L,48203L,48204L,48205L,48206L,48207L,
93838 48208L,48209L,48210L,48211L,48212L,48213L,48214L,48215L,48216L,48217L,
93839 48218L,48219L,48220L,48221L,48222L,48223L,48224L,48225L,48226L,48227L,
93840 48228L,48229L,48230L,48231L,48232L,48233L,48234L,48235L,48236L,48237L,
93841 48238L,48239L,48240L,48241L,48242L,48243L,48244L,48245L,48246L,48247L,
93842 48248L,48249L,48250L,48251L,48252L,48253L,48254L,48255L,48256L,48257L,
93843 48258L,48259L,48260L,48261L,48262L,48263L,48264L,48265L,48266L,48267L,
93844 48268L,48269L,48270L,48271L,48272L,48273L,48274L,48275L,48276L,48277L,
93845 48278L,48279L,48280L,48281L,48282L,48283L,48284L,48285L,48286L,48287L,
93846 48288L,48289L,48290L,48291L,48292L,48293L,48294L,48295L,48296L,48297L,
93847 48298L,48299L,48300L,48301L,48302L,48303L,48304L,48305L,48306L,48307L,
93848 48308L,48309L,48310L,48311L,48312L,48313L,48314L,48315L,48316L,48317L,
93849 48318L,48319L,48320L,48321L,48322L,48323L,48324L,48325L,48326L,48327L,
93850 48328L,48329L,48330L,48331L,48332L,48333L,48334L,48335L,48336L,48337L,
93851 48338L,48339L,48340L,48341L,48342L,48343L,48344L,48345L,48346L,48347L,
93852 48348L,48349L,48350L,48351L,48352L,48353L,48354L,48355L,48356L,48357L,
93853 48358L,48359L,48360L,48361L,48362L,48363L,48364L,48365L,48366L,48367L,
93854 48368L,48369L,48370L,48371L,48372L,48373L,48374L,48375L,48376L,48377L,
93855 48378L,48379L,48380L,48381L,48382L,48383L,48384L,48385L,48386L,48387L,
93856 48388L,48389L,48390L,48391L,48392L,48393L,48394L,48395L,48396L,48397L,
93857 48398L,48399L,48400L,48401L,48402L,48403L,48404L,48405L,48406L,48407L,
93858 48408L,48409L,48410L,48411L,48412L,48413L,48414L,48415L,48416L,48417L,
93859 48418L,48419L,48420L,48421L,48422L,48423L,48424L,48425L,48426L,48427L,
93860 48428L,48429L,48430L,48431L,48432L,48433L,48434L,48435L,48436L,48437L,
93861 48438L,48439L,48440L,48441L,48442L,48443L,48444L,48445L,48446L,48447L,
93862 48448L,48449L,48450L,48451L,48452L,48453L,48454L,48455L,48456L,48457L,
93863 48458L,48459L,48460L,48461L,48462L,48463L,48464L,48465L,48466L,48467L,
93864 48468L,48469L,48470L,48471L,48472L,48473L,48474L,48475L,48476L,48477L,
93865 48478L,48479L,48480L,48481L,48482L,48483L,48484L,48485L,48486L,48487L,
93866 48488L,48489L,48490L,48491L,48492L,48493L,48494L,48495L,48496L,48497L,
93867 48498L,48499L,48500L,48501L,48502L,48503L,48504L,48505L,48506L,48507L,
93868 48508L,48509L,48510L,48511L,48512L,48513L,48514L,48515L,48516L,48517L,
93869 48518L,48519L,48520L,48521L,48522L,48523L,48524L,48525L,48526L,48527L,
93870 48528L,48529L,48530L,48531L,48532L,48533L,48534L,48535L,48536L,48537L,
93871 48538L,48539L,48540L,48541L,48542L,48543L,48544L,48545L,48546L,48547L,
93872 48548L,48549L,48550L,48551L,48552L,48553L,48554L,48555L,48556L,48557L,
93873 48558L,48559L,48560L,48561L,48562L,48563L,48564L,48565L,48566L,48567L,
93874 48568L,48569L,48570L,48571L,48572L,48573L,48574L,48575L,48576L,48577L,
93875 48578L,48579L,48580L,48581L,48582L,48583L,48584L,48585L,48586L,48587L,
93876 48588L,48589L,48590L,48591L,48592L,48593L,48594L,48595L,48596L,48597L,
93877 48598L,48599L,48600L,48601L,48602L,48603L,48604L,48605L,48606L,48607L,
93878 48608L,48609L,48610L,48611L,48612L,48613L,48614L,48615L,48616L,48617L,
93879 48618L,48619L,48620L,48621L,48622L,48623L,48624L,48625L,48626L,48627L,
93880 48628L,48629L,48630L,48631L,48632L,48633L,48634L,48635L,48636L,48637L,
93881 48638L,48639L,48640L,48641L,48642L,48643L,48644L,48645L,48646L,48647L,
93882 48648L,48649L,48650L,48651L,48652L,48653L,48654L,48655L,48656L,48657L,
93883 48658L,48659L,48660L,48661L,48662L,48663L,48664L,48665L,48666L,48667L,
93884 48668L,48669L,48670L,48671L,48672L,48673L,48674L,48675L,48676L,48677L,
93885 48678L,48679L,48680L,48681L,48682L,48683L,48684L,48685L,48686L,48687L,
93886 48688L,48689L,48690L,48691L,48692L,48693L,48694L,48695L,48696L,48697L,
93887 48698L,48699L,48700L,48701L,48702L,48703L,48704L,48705L,48706L,48707L,
93888 48708L,48709L,48710L,48711L,48712L,48713L,48714L,48715L,48716L,48717L,
93889 48718L,48719L,48720L,48721L,48722L,48723L,48724L,48725L,48726L,48727L,
93890 48728L,48729L,48730L,48731L,48732L,48733L,48734L,48735L,48736L,48737L,
93891 48738L,48739L,48740L,48741L,48742L,48743L,48744L,48745L,48746L,48747L,
93892 48748L,48749L,48750L,48751L,48752L,48753L,48754L,48755L,48756L,48757L,
93893 48758L,48759L,48760L,48761L,48762L,48763L,48764L,48765L,48766L,48767L,
93894 48768L,48769L,48770L,48771L,48772L,48773L,48774L,48775L,48776L,48777L,
93895 48778L,48779L,48780L,48781L,48782L,48783L,48784L,48785L,48786L,48787L,
93896 48788L,48789L,48790L,48791L,48792L,48793L,48794L,48795L,48796L,48797L,
93897 48798L,48799L,48800L,48801L,48802L,48803L,48804L,48805L,48806L,48807L,
93898 48808L,48809L,48810L,48811L,48812L,48813L,48814L,48815L,48816L,48817L,
93899 48818L,48819L,48820L,48821L,48822L,48823L,48824L,48825L,48826L,48827L,
93900 48828L,48829L,48830L,48831L,48832L,48833L,48834L,48835L,48836L,48837L,
93901 48838L,48839L,48840L,48841L,48842L,48843L,48844L,48845L,48846L,48847L,
93902 48848L,48849L,48850L,48851L,48852L,48853L,48854L,48855L,48856L,48857L,
93903 48858L,48859L,48860L,48861L,48862L,48863L,48864L,48865L,48866L,48867L,
93904 48868L,48869L,48870L,48871L,48872L,48873L,48874L,48875L,48876L,48877L,
93905 48878L,48879L,48880L,48881L,48882L,48883L,48884L,48885L,48886L,48887L,
93906 48888L,48889L,48890L,48891L,48892L,48893L,48894L,48895L,48896L,48897L,
93907 48898L,48899L,48900L,48901L,48902L,48903L,48904L,48905L,48906L,48907L,
93908 48908L,48909L,48910L,48911L,48912L,48913L,48914L,48915L,48916L,48917L,
93909 48918L,48919L,48920L,48921L,48922L,48923L,48924L,48925L,48926L,48927L,
93910 48928L,48929L,48930L,48931L,48932L,48933L,48934L,48935L,48936L,48937L,
93911 48938L,48939L,48940L,48941L,48942L,48943L,48944L,48945L,48946L,48947L,
93912 48948L,48949L,48950L,48951L,48952L,48953L,48954L,48955L,48956L,48957L,
93913 48958L,48959L,48960L,48961L,48962L,48963L,48964L,48965L,48966L,48967L,
93914 48968L,48969L,48970L,48971L,48972L,48973L,48974L,48975L,48976L,48977L,
93915 48978L,48979L,48980L,48981L,48982L,48983L,48984L,48985L,48986L,48987L,
93916 48988L,48989L,48990L,48991L,48992L,48993L,48994L,48995L,48996L,48997L,
93917 48998L,48999L,49000L,49001L,49002L,49003L,49004L,49005L,49006L,49007L,
93918 49008L,49009L,49010L,49011L,49012L,49013L,49014L,49015L,49016L,49017L,
93919 49018L,49019L,49020L,49021L,49022L,49023L,49024L,49025L,49026L,49027L,
93920 49028L,49029L,49030L,49031L,49032L,49033L,49034L,49035L,49036L,49037L,
93921 49038L,49039L,49040L,49041L,49042L,49043L,49044L,49045L,49046L,49047L,
93922 49048L,49049L,49050L,49051L,49052L,49053L,49054L,49055L,49056L,49057L,
93923 49058L,49059L,49060L,49061L,49062L,49063L,49064L,49065L,49066L,49067L,
93924 49068L,49069L,49070L,49071L,49072L,49073L,49074L,49075L,49076L,49077L,
93925 49078L,49079L,49080L,49081L,49082L,49083L,49084L,49085L,49086L,49087L,
93926 49088L,49089L,49090L,49091L,49092L,49093L,49094L,49095L,49096L,49097L,
93927 49098L,49099L,49100L,49101L,49102L,49103L,49104L,49105L,49106L,49107L,
93928 49108L,49109L,49110L,49111L,49112L,49113L,49114L,49115L,49116L,49117L,
93929 49118L,49119L,49120L,49121L,49122L,49123L,49124L,49125L,49126L,49127L,
93930 49128L,49129L,49130L,49131L,49132L,49133L,49134L,49135L,49136L,49137L,
93931 49138L,49139L,49140L,49141L,49142L,49143L,49144L,49145L,49146L,49147L,
93932 49148L,49149L,49150L,49151L,49152L,49153L,49154L,49155L,49156L,49157L,
93933 49158L,49159L,49160L,49161L,49162L,49163L,49164L,49165L,49166L,49167L,
93934 49168L,49169L,49170L,49171L,49172L,49173L,49174L,49175L,49176L,49177L,
93935 49178L,49179L,49180L,49181L,49182L,49183L,49184L,49185L,49186L,49187L,
93936 49188L,49189L,49190L,49191L,49192L,49193L,49194L,49195L,49196L,49197L,
93937 49198L,49199L,49200L,49201L,49202L,49203L,49204L,49205L,49206L,49207L,
93938 49208L,49209L,49210L,49211L,49212L,49213L,49214L,49215L,49216L,49217L,
93939 49218L,49219L,49220L,49221L,49222L,49223L,49224L,49225L,49226L,49227L,
93940 49228L,49229L,49230L,49231L,49232L,49233L,49234L,49235L,49236L,49237L,
93941 49238L,49239L,49240L,49241L,49242L,49243L,49244L,49245L,49246L,49247L,
93942 49248L,49249L,49250L,49251L,49252L,49253L,49254L,49255L,49256L,49257L,
93943 49258L,49259L,49260L,49261L,49262L,49263L,49264L,49265L,49266L,49267L,
93944 49268L,49269L,49270L,49271L,49272L,49273L,49274L,49275L,49276L,49277L,
93945 49278L,49279L,49280L,49281L,49282L,49283L,49284L,49285L,49286L,49287L,
93946 49288L,49289L,49290L,49291L,49292L,49293L,49294L,49295L,49296L,49297L,
93947 49298L,49299L,49300L,49301L,49302L,49303L,49304L,49305L,49306L,49307L,
93948 49308L,49309L,49310L,49311L,49312L,49313L,49314L,49315L,49316L,49317L,
93949 49318L,49319L,49320L,49321L,49322L,49323L,49324L,49325L,49326L,49327L,
93950 49328L,49329L,49330L,49331L,49332L,49333L,49334L,49335L,49336L,49337L,
93951 49338L,49339L,49340L,49341L,49342L,49343L,49344L,49345L,49346L,49347L,
93952 49348L,49349L,49350L,49351L,49352L,49353L,49354L,49355L,49356L,49357L,
93953 49358L,49359L,49360L,49361L,49362L,49363L,49364L,49365L,49366L,49367L,
93954 49368L,49369L,49370L,49371L,49372L,49373L,49374L,49375L,49376L,49377L,
93955 49378L,49379L,49380L,49381L,49382L,49383L,49384L,49385L,49386L,49387L,
93956 49388L,49389L,49390L,49391L,49392L,49393L,49394L,49395L,49396L,49397L,
93957 49398L,49399L,49400L,49401L,49402L,49403L,49404L,49405L,49406L,49407L,
93958 49408L,49409L,49410L,49411L,49412L,49413L,49414L,49415L,49416L,49417L,
93959 49418L,49419L,49420L,49421L,49422L,49423L,49424L,49425L,49426L,49427L,
93960 49428L,49429L,49430L,49431L,49432L,49433L,49434L,49435L,49436L,49437L,
93961 49438L,49439L,49440L,49441L,49442L,49443L,49444L,49445L,49446L,49447L,
93962 49448L,49449L,49450L,49451L,49452L,49453L,49454L,49455L,49456L,49457L,
93963 49458L,49459L,49460L,49461L,49462L,49463L,49464L,49465L,49466L,49467L,
93964 49468L,49469L,49470L,49471L,49472L,49473L,49474L,49475L,49476L,49477L,
93965 49478L,49479L,49480L,49481L,49482L,49483L,49484L,49485L,49486L,49487L,
93966 49488L,49489L,49490L,49491L,49492L,49493L,49494L,49495L,49496L,49497L,
93967 49498L,49499L,49500L,49501L,49502L,49503L,49504L,49505L,49506L,49507L,
93968 49508L,49509L,49510L,49511L,49512L,49513L,49514L,49515L,49516L,49517L,
93969 49518L,49519L,49520L,49521L,49522L,49523L,49524L,49525L,49526L,49527L,
93970 49528L,49529L,49530L,49531L,49532L,49533L,49534L,49535L,49536L,49537L,
93971 49538L,49539L,49540L,49541L,49542L,49543L,49544L,49545L,49546L,49547L,
93972 49548L,49549L,49550L,49551L,49552L,49553L,49554L,49555L,49556L,49557L,
93973 49558L,49559L,49560L,49561L,49562L,49563L,49564L,49565L,49566L,49567L,
93974 49568L,49569L,49570L,49571L,49572L,49573L,49574L,49575L,49576L,49577L,
93975 49578L,49579L,49580L,49581L,49582L,49583L,49584L,49585L,49586L,49587L,
93976 49588L,49589L,49590L,49591L,49592L,49593L,49594L,49595L,49596L,49597L,
93977 49598L,49599L,49600L,49601L,49602L,49603L,49604L,49605L,49606L,49607L,
93978 49608L,49609L,49610L,49611L,49612L,49613L,49614L,49615L,49616L,49617L,
93979 49618L,49619L,49620L,49621L,49622L,49623L,49624L,49625L,49626L,49627L,
93980 49628L,49629L,49630L,49631L,49632L,49633L,49634L,49635L,49636L,49637L,
93981 49638L,49639L,49640L,49641L,49642L,49643L,49644L,49645L,49646L,49647L,
93982 49648L,49649L,49650L,49651L,49652L,49653L,49654L,49655L,49656L,49657L,
93983 49658L,49659L,49660L,49661L,49662L,49663L,49664L,49665L,49666L,49667L,
93984 49668L,49669L,49670L,49671L,49672L,49673L,49674L,49675L,49676L,49677L,
93985 49678L,49679L,49680L,49681L,49682L,49683L,49684L,49685L,49686L,49687L,
93986 49688L,49689L,49690L,49691L,49692L,49693L,49694L,49695L,49696L,49697L,
93987 49698L,49699L,49700L,49701L,49702L,49703L,49704L,49705L,49706L,49707L,
93988 49708L,49709L,49710L,49711L,49712L,49713L,49714L,49715L,49716L,49717L,
93989 49718L,49719L,49720L,49721L,49722L,49723L,49724L,49725L,49726L,49727L,
93990 49728L,49729L,49730L,49731L,49732L,49733L,49734L,49735L,49736L,49737L,
93991 49738L,49739L,49740L,49741L,49742L,49743L,49744L,49745L,49746L,49747L,
93992 49748L,49749L,49750L,49751L,49752L,49753L,49754L,49755L,49756L,49757L,
93993 49758L,49759L,49760L,49761L,49762L,49763L,49764L,49765L,49766L,49767L,
93994 49768L,49769L,49770L,49771L,49772L,49773L,49774L,49775L,49776L,49777L,
93995 49778L,49779L,49780L,49781L,49782L,49783L,49784L,49785L,49786L,49787L,
93996 49788L,49789L,49790L,49791L,49792L,49793L,49794L,49795L,49796L,49797L,
93997 49798L,49799L,49800L,49801L,49802L,49803L,49804L,49805L,49806L,49807L,
93998 49808L,49809L,49810L,49811L,49812L,49813L,49814L,49815L,49816L,49817L,
93999 49818L,49819L,49820L,49821L,49822L,49823L,49824L,49825L,49826L,49827L,
94000 49828L,49829L,49830L,49831L,49832L,49833L,49834L,49835L,49836L,49837L,
94001 49838L,49839L,49840L,49841L,49842L,49843L,49844L,49845L,49846L,49847L,
94002 49848L,49849L,49850L,49851L,49852L,49853L,49854L,49855L,49856L,49857L,
94003 49858L,49859L,49860L,49861L,49862L,49863L,49864L,49865L,49866L,49867L,
94004 49868L,49869L,49870L,49871L,49872L,49873L,49874L,49875L,49876L,49877L,
94005 49878L,49879L,49880L,49881L,49882L,49883L,49884L,49885L,49886L,49887L,
94006 49888L,49889L,49890L,49891L,49892L,49893L,49894L,49895L,49896L,49897L,
94007 49898L,49899L,49900L,49901L,49902L,49903L,49904L,49905L,49906L,49907L,
94008 49908L,49909L,49910L,49911L,49912L,49913L,49914L,49915L,49916L,49917L,
94009 49918L,49919L,49920L,49921L,49922L,49923L,49924L,49925L,49926L,49927L,
94010 49928L,49929L,49930L,49931L,49932L,49933L,49934L,49935L,49936L,49937L,
94011 49938L,49939L,49940L,49941L,49942L,49943L,49944L,49945L,49946L,49947L,
94012 49948L,49949L,49950L,49951L,49952L,49953L,49954L,49955L,49956L,49957L,
94013 49958L,49959L,49960L,49961L,49962L,49963L,49964L,49965L,49966L,49967L,
94014 49968L,49969L,49970L,49971L,49972L,49973L,49974L,49975L,49976L,49977L,
94015 49978L,49979L,49980L,49981L,49982L,49983L,49984L,49985L,49986L,49987L,
94016 49988L,49989L,49990L,49991L,49992L,49993L,49994L,49995L,49996L,49997L,
94017 49998L,49999L,50000L,50001L,50002L,50003L,50004L,50005L,50006L,50007L,
94018 50008L,50009L,50010L,50011L,50012L,50013L,50014L,50015L,50016L,50017L,
94019 50018L,50019L,50020L,50021L,50022L,50023L,50024L,50025L,50026L,50027L,
94020 50028L,50029L,50030L,50031L,50032L,50033L,50034L,50035L,50036L,50037L,
94021 50038L,50039L,50040L,50041L,50042L,50043L,50044L,50045L,50046L,50047L,
94022 50048L,50049L,50050L,50051L,50052L,50053L,50054L,50055L,50056L,50057L,
94023 50058L,50059L,50060L,50061L,50062L,50063L,50064L,50065L,50066L,50067L,
94024 50068L,50069L,50070L,50071L,50072L,50073L,50074L,50075L,50076L,50077L,
94025 50078L,50079L,50080L,50081L,50082L,50083L,50084L,50085L,50086L,50087L,
94026 50088L,50089L,50090L,50091L,50092L,50093L,50094L,50095L,50096L,50097L,
94027 50098L,50099L,50100L,50101L,50102L,50103L,50104L,50105L,50106L,50107L,
94028 50108L,50109L,50110L,50111L,50112L,50113L,50114L,50115L,50116L,50117L,
94029 50118L,50119L,50120L,50121L,50122L,50123L,50124L,50125L,50126L,50127L,
94030 50128L,50129L,50130L,50131L,50132L,50133L,50134L,50135L,50136L,50137L,
94031 50138L,50139L,50140L,50141L,50142L,50143L,50144L,50145L,50146L,50147L,
94032 50148L,50149L,50150L,50151L,50152L,50153L,50154L,50155L,50156L,50157L,
94033 50158L,50159L,50160L,50161L,50162L,50163L,50164L,50165L,50166L,50167L,
94034 50168L,50169L,50170L,50171L,50172L,50173L,50174L,50175L,50176L,50177L,
94035 50178L,50179L,50180L,50181L,50182L,50183L,50184L,50185L,50186L,50187L,
94036 50188L,50189L,50190L,50191L,50192L,50193L,50194L,50195L,50196L,50197L,
94037 50198L,50199L,50200L,50201L,50202L,50203L,50204L,50205L,50206L,50207L,
94038 50208L,50209L,50210L,50211L,50212L,50213L,50214L,50215L,50216L,50217L,
94039 50218L,50219L,50220L,50221L,50222L,50223L,50224L,50225L,50226L,50227L,
94040 50228L,50229L,50230L,50231L,50232L,50233L,50234L,50235L,50236L,50237L,
94041 50238L,50239L,50240L,50241L,50242L,50243L,50244L,50245L,50246L,50247L,
94042 50248L,50249L,50250L,50251L,50252L,50253L,50254L,50255L,50256L,50257L,
94043 50258L,50259L,50260L,50261L,50262L,50263L,50264L,50265L,50266L,50267L,
94044 50268L,50269L,50270L,50271L,50272L,50273L,50274L,50275L,50276L,50277L,
94045 50278L,50279L,50280L,50281L,50282L,50283L,50284L,50285L,50286L,50287L,
94046 50288L,50289L,50290L,50291L,50292L,50293L,50294L,50295L,50296L,50297L,
94047 50298L,50299L,50300L,50301L,50302L,50303L,50304L,50305L,50306L,50307L,
94048 50308L,50309L,50310L,50311L,50312L,50313L,50314L,50315L,50316L,50317L,
94049 50318L,50319L,50320L,50321L,50322L,50323L,50324L,50325L,50326L,50327L,
94050 50328L,50329L,50330L,50331L,50332L,50333L,50334L,50335L,50336L,50337L,
94051 50338L,50339L,50340L,50341L,50342L,50343L,50344L,50345L,50346L,50347L,
94052 50348L,50349L,50350L,50351L,50352L,50353L,50354L,50355L,50356L,50357L,
94053 50358L,50359L,50360L,50361L,50362L,50363L,50364L,50365L,50366L,50367L,
94054 50368L,50369L,50370L,50371L,50372L,50373L,50374L,50375L,50376L,50377L,
94055 50378L,50379L,50380L,50381L,50382L,50383L,50384L,50385L,50386L,50387L,
94056 50388L,50389L,50390L,50391L,50392L,50393L,50394L,50395L,50396L,50397L,
94057 50398L,50399L,50400L,50401L,50402L,50403L,50404L,50405L,50406L,50407L,
94058 50408L,50409L,50410L,50411L,50412L,50413L,50414L,50415L,50416L,50417L,
94059 50418L,50419L,50420L,50421L,50422L,50423L,50424L,50425L,50426L,50427L,
94060 50428L,50429L,50430L,50431L,50432L,50433L,50434L,50435L,50436L,50437L,
94061 50438L,50439L,50440L,50441L,50442L,50443L,50444L,50445L,50446L,50447L,
94062 50448L,50449L,50450L,50451L,50452L,50453L,50454L,50455L,50456L,50457L,
94063 50458L,50459L,50460L,50461L,50462L,50463L,50464L,50465L,50466L,50467L,
94064 50468L,50469L,50470L,50471L,50472L,50473L,50474L,50475L,50476L,50477L,
94065 50478L,50479L,50480L,50481L,50482L,50483L,50484L,50485L,50486L,50487L,
94066 50488L,50489L,50490L,50491L,50492L,50493L,50494L,50495L,50496L,50497L,
94067 50498L,50499L,50500L,50501L,50502L,50503L,50504L,50505L,50506L,50507L,
94068 50508L,50509L,50510L,50511L,50512L,50513L,50514L,50515L,50516L,50517L,
94069 50518L,50519L,50520L,50521L,50522L,50523L,50524L,50525L,50526L,50527L,
94070 50528L,50529L,50530L,50531L,50532L,50533L,50534L,50535L,50536L,50537L,
94071 50538L,50539L,50540L,50541L,50542L,50543L,50544L,50545L,50546L,50547L,
94072 50548L,50549L,50550L,50551L,50552L,50553L,50554L,50555L,50556L,50557L,
94073 50558L,50559L,50560L,50561L,50562L,50563L,50564L,50565L,50566L,50567L,
94074 50568L,50569L,50570L,50571L,50572L,50573L,50574L,50575L,50576L,50577L,
94075 50578L,50579L,50580L,50581L,50582L,50583L,50584L,50585L,50586L,50587L,
94076 50588L,50589L,50590L,50591L,50592L,50593L,50594L,50595L,50596L,50597L,
94077 50598L,50599L,50600L,50601L,50602L,50603L,50604L,50605L,50606L,50607L,
94078 50608L,50609L,50610L,50611L,50612L,50613L,50614L,50615L,50616L,50617L,
94079 50618L,50619L,50620L,50621L,50622L,50623L,50624L,50625L,50626L,50627L,
94080 50628L,50629L,50630L,50631L,50632L,50633L,50634L,50635L,50636L,50637L,
94081 50638L,50639L,50640L,50641L,50642L,50643L,50644L,50645L,50646L,50647L,
94082 50648L,50649L,50650L,50651L,50652L,50653L,50654L,50655L,50656L,50657L,
94083 50658L,50659L,50660L,50661L,50662L,50663L,50664L,50665L,50666L,50667L,
94084 50668L,50669L,50670L,50671L,50672L,50673L,50674L,50675L,50676L,50677L,
94085 50678L,50679L,50680L,50681L,50682L,50683L,50684L,50685L,50686L,50687L,
94086 50688L,50689L,50690L,50691L,50692L,50693L,50694L,50695L,50696L,50697L,
94087 50698L,50699L,50700L,50701L,50702L,50703L,50704L,50705L,50706L,50707L,
94088 50708L,50709L,50710L,50711L,50712L,50713L,50714L,50715L,50716L,50717L,
94089 50718L,50719L,50720L,50721L,50722L,50723L,50724L,50725L,50726L,50727L,
94090 50728L,50729L,50730L,50731L,50732L,50733L,50734L,50735L,50736L,50737L,
94091 50738L,50739L,50740L,50741L,50742L,50743L,50744L,50745L,50746L,50747L,
94092 50748L,50749L,50750L,50751L,50752L,50753L,50754L,50755L,50756L,50757L,
94093 50758L,50759L,50760L,50761L,50762L,50763L,50764L,50765L,50766L,50767L,
94094 50768L,50769L,50770L,50771L,50772L,50773L,50774L,50775L,50776L,50777L,
94095 50778L,50779L,50780L,50781L,50782L,50783L,50784L,50785L,50786L,50787L,
94096 50788L,50789L,50790L,50791L,50792L,50793L,50794L,50795L,50796L,50797L,
94097 50798L,50799L,50800L,50801L,50802L,50803L,50804L,50805L,50806L,50807L,
94098 50808L,50809L,50810L,50811L,50812L,50813L,50814L,50815L,50816L,50817L,
94099 50818L,50819L,50820L,50821L,50822L,50823L,50824L,50825L,50826L,50827L,
94100 50828L,50829L,50830L,50831L,50832L,50833L,50834L,50835L,50836L,50837L,
94101 50838L,50839L,50840L,50841L,50842L,50843L,50844L,50845L,50846L,50847L,
94102 50848L,50849L,50850L,50851L,50852L,50853L,50854L,50855L,50856L,50857L,
94103 50858L,50859L,50860L,50861L,50862L,50863L,50864L,50865L,50866L,50867L,
94104 50868L,50869L,50870L,50871L,50872L,50873L,50874L,50875L,50876L,50877L,
94105 50878L,50879L,50880L,50881L,50882L,50883L,50884L,50885L,50886L,50887L,
94106 50888L,50889L,50890L,50891L,50892L,50893L,50894L,50895L,50896L,50897L,
94107 50898L,50899L,50900L,50901L,50902L,50903L,50904L,50905L,50906L,50907L,
94108 50908L,50909L,50910L,50911L,50912L,50913L,50914L,50915L,50916L,50917L,
94109 50918L,50919L,50920L,50921L,50922L,50923L,50924L,50925L,50926L,50927L,
94110 50928L,50929L,50930L,50931L,50932L,50933L,50934L,50935L,50936L,50937L,
94111 50938L,50939L,50940L,50941L,50942L,50943L,50944L,50945L,50946L,50947L,
94112 50948L,50949L,50950L,50951L,50952L,50953L,50954L,50955L,50956L,50957L,
94113 50958L,50959L,50960L,50961L,50962L,50963L,50964L,50965L,50966L,50967L,
94114 50968L,50969L,50970L,50971L,50972L,50973L,50974L,50975L,50976L,50977L,
94115 50978L,50979L,50980L,50981L,50982L,50983L,50984L,50985L,50986L,50987L,
94116 50988L,50989L,50990L,50991L,50992L,50993L,50994L,50995L,50996L,50997L,
94117 50998L,50999L,51000L,51001L,51002L,51003L,51004L,51005L,51006L,51007L,
94118 51008L,51009L,51010L,51011L,51012L,51013L,51014L,51015L,51016L,51017L,
94119 51018L,51019L,51020L,51021L,51022L,51023L,51024L,51025L,51026L,51027L,
94120 51028L,51029L,51030L,51031L,51032L,51033L,51034L,51035L,51036L,51037L,
94121 51038L,51039L,51040L,51041L,51042L,51043L,51044L,51045L,51046L,51047L,
94122 51048L,51049L,51050L,51051L,51052L,51053L,51054L,51055L,51056L,51057L,
94123 51058L,51059L,51060L,51061L,51062L,51063L,51064L,51065L,51066L,51067L,
94124 51068L,51069L,51070L,51071L,51072L,51073L,51074L,51075L,51076L,51077L,
94125 51078L,51079L,51080L,51081L,51082L,51083L,51084L,51085L,51086L,51087L,
94126 51088L,51089L,51090L,51091L,51092L,51093L,51094L,51095L,51096L,51097L,
94127 51098L,51099L,51100L,51101L,51102L,51103L,51104L,51105L,51106L,51107L,
94128 51108L,51109L,51110L,51111L,51112L,51113L,51114L,51115L,51116L,51117L,
94129 51118L,51119L,51120L,51121L,51122L,51123L,51124L,51125L,51126L,51127L,
94130 51128L,51129L,51130L,51131L,51132L,51133L,51134L,51135L,51136L,51137L,
94131 51138L,51139L,51140L,51141L,51142L,51143L,51144L,51145L,51146L,51147L,
94132 51148L,51149L,51150L,51151L,51152L,51153L,51154L,51155L,51156L,51157L,
94133 51158L,51159L,51160L,51161L,51162L,51163L,51164L,51165L,51166L,51167L,
94134 51168L,51169L,51170L,51171L,51172L,51173L,51174L,51175L,51176L,51177L,
94135 51178L,51179L,51180L,51181L,51182L,51183L,51184L,51185L,51186L,51187L,
94136 51188L,51189L,51190L,51191L,51192L,51193L,51194L,51195L,51196L,51197L,
94137 51198L,51199L,51200L,51201L,51202L,51203L,51204L,51205L,51206L,51207L,
94138 51208L,51209L,51210L,51211L,51212L,51213L,51214L,51215L,51216L,51217L,
94139 51218L,51219L,51220L,51221L,51222L,51223L,51224L,51225L,51226L,51227L,
94140 51228L,51229L,51230L,51231L,51232L,51233L,51234L,51235L,51236L,51237L,
94141 51238L,51239L,51240L,51241L,51242L,51243L,51244L,51245L,51246L,51247L,
94142 51248L,51249L,51250L,51251L,51252L,51253L,51254L,51255L,51256L,51257L,
94143 51258L,51259L,51260L,51261L,51262L,51263L,51264L,51265L,51266L,51267L,
94144 51268L,51269L,51270L,51271L,51272L,51273L,51274L,51275L,51276L,51277L,
94145 51278L,51279L,51280L,51281L,51282L,51283L,51284L,51285L,51286L,51287L,
94146 51288L,51289L,51290L,51291L,51292L,51293L,51294L,51295L,51296L,51297L,
94147 51298L,51299L,51300L,51301L,51302L,51303L,51304L,51305L,51306L,51307L,
94148 51308L,51309L,51310L,51311L,51312L,51313L,51314L,51315L,51316L,51317L,
94149 51318L,51319L,51320L,51321L,51322L,51323L,51324L,51325L,51326L,51327L,
94150 51328L,51329L,51330L,51331L,51332L,51333L,51334L,51335L,51336L,51337L,
94151 51338L,51339L,51340L,51341L,51342L,51343L,51344L,51345L,51346L,51347L,
94152 51348L,51349L,51350L,51351L,51352L,51353L,51354L,51355L,51356L,51357L,
94153 51358L,51359L,51360L,51361L,51362L,51363L,51364L,51365L,51366L,51367L,
94154 51368L,51369L,51370L,51371L,51372L,51373L,51374L,51375L,51376L,51377L,
94155 51378L,51379L,51380L,51381L,51382L,51383L,51384L,51385L,51386L,51387L,
94156 51388L,51389L,51390L,51391L,51392L,51393L,51394L,51395L,51396L,51397L,
94157 51398L,51399L,51400L,51401L,51402L,51403L,51404L,51405L,51406L,51407L,
94158 51408L,51409L,51410L,51411L,51412L,51413L,51414L,51415L,51416L,51417L,
94159 51418L,51419L,51420L,51421L,51422L,51423L,51424L,51425L,51426L,51427L,
94160 51428L,51429L,51430L,51431L,51432L,51433L,51434L,51435L,51436L,51437L,
94161 51438L,51439L,51440L,51441L,51442L,51443L,51444L,51445L,51446L,51447L,
94162 51448L,51449L,51450L,51451L,51452L,51453L,51454L,51455L,51456L,51457L,
94163 51458L,51459L,51460L,51461L,51462L,51463L,51464L,51465L,51466L,51467L,
94164 51468L,51469L,51470L,51471L,51472L,51473L,51474L,51475L,51476L,51477L,
94165 51478L,51479L,51480L,51481L,51482L,51483L,51484L,51485L,51486L,51487L,
94166 51488L,51489L,51490L,51491L,51492L,51493L,51494L,51495L,51496L,51497L,
94167 51498L,51499L,51500L,51501L,51502L,51503L,51504L,51505L,51506L,51507L,
94168 51508L,51509L,51510L,51511L,51512L,51513L,51514L,51515L,51516L,51517L,
94169 51518L,51519L,51520L,51521L,51522L,51523L,51524L,51525L,51526L,51527L,
94170 51528L,51529L,51530L,51531L,51532L,51533L,51534L,51535L,51536L,51537L,
94171 51538L,51539L,51540L,51541L,51542L,51543L,51544L,51545L,51546L,51547L,
94172 51548L,51549L,51550L,51551L,51552L,51553L,51554L,51555L,51556L,51557L,
94173 51558L,51559L,51560L,51561L,51562L,51563L,51564L,51565L,51566L,51567L,
94174 51568L,51569L,51570L,51571L,51572L,51573L,51574L,51575L,51576L,51577L,
94175 51578L,51579L,51580L,51581L,51582L,51583L,51584L,51585L,51586L,51587L,
94176 51588L,51589L,51590L,51591L,51592L,51593L,51594L,51595L,51596L,51597L,
94177 51598L,51599L,51600L,51601L,51602L,51603L,51604L,51605L,51606L,51607L,
94178 51608L,51609L,51610L,51611L,51612L,51613L,51614L,51615L,51616L,51617L,
94179 51618L,51619L,51620L,51621L,51622L,51623L,51624L,51625L,51626L,51627L,
94180 51628L,51629L,51630L,51631L,51632L,51633L,51634L,51635L,51636L,51637L,
94181 51638L,51639L,51640L,51641L,51642L,51643L,51644L,51645L,51646L,51647L,
94182 51648L,51649L,51650L,51651L,51652L,51653L,51654L,51655L,51656L,51657L,
94183 51658L,51659L,51660L,51661L,51662L,51663L,51664L,51665L,51666L,51667L,
94184 51668L,51669L,51670L,51671L,51672L,51673L,51674L,51675L,51676L,51677L,
94185 51678L,51679L,51680L,51681L,51682L,51683L,51684L,51685L,51686L,51687L,
94186 51688L,51689L,51690L,51691L,51692L,51693L,51694L,51695L,51696L,51697L,
94187 51698L,51699L,51700L,51701L,51702L,51703L,51704L,51705L,51706L,51707L,
94188 51708L,51709L,51710L,51711L,51712L,51713L,51714L,51715L,51716L,51717L,
94189 51718L,51719L,51720L,51721L,51722L,51723L,51724L,51725L,51726L,51727L,
94190 51728L,51729L,51730L,51731L,51732L,51733L,51734L,51735L,51736L,51737L,
94191 51738L,51739L,51740L,51741L,51742L,51743L,51744L,51745L,51746L,51747L,
94192 51748L,51749L,51750L,51751L,51752L,51753L,51754L,51755L,51756L,51757L,
94193 51758L,51759L,51760L,51761L,51762L,51763L,51764L,51765L,51766L,51767L,
94194 51768L,51769L,51770L,51771L,51772L,51773L,51774L,51775L,51776L,51777L,
94195 51778L,51779L,51780L,51781L,51782L,51783L,51784L,51785L,51786L,51787L,
94196 51788L,51789L,51790L,51791L,51792L,51793L,51794L,51795L,51796L,51797L,
94197 51798L,51799L,51800L,51801L,51802L,51803L,51804L,51805L,51806L,51807L,
94198 51808L,51809L,51810L,51811L,51812L,51813L,51814L,51815L,51816L,51817L,
94199 51818L,51819L,51820L,51821L,51822L,51823L,51824L,51825L,51826L,51827L,
94200 51828L,51829L,51830L,51831L,51832L,51833L,51834L,51835L,51836L,51837L,
94201 51838L,51839L,51840L,51841L,51842L,51843L,51844L,51845L,51846L,51847L,
94202 51848L,51849L,51850L,51851L,51852L,51853L,51854L,51855L,51856L,51857L,
94203 51858L,51859L,51860L,51861L,51862L,51863L,51864L,51865L,51866L,51867L,
94204 51868L,51869L,51870L,51871L,51872L,51873L,51874L,51875L,51876L,51877L,
94205 51878L,51879L,51880L,51881L,51882L,51883L,51884L,51885L,51886L,51887L,
94206 51888L,51889L,51890L,51891L,51892L,51893L,51894L,51895L,51896L,51897L,
94207 51898L,51899L,51900L,51901L,51902L,51903L,51904L,51905L,51906L,51907L,
94208 51908L,51909L,51910L,51911L,51912L,51913L,51914L,51915L,51916L,51917L,
94209 51918L,51919L,51920L,51921L,51922L,51923L,51924L,51925L,51926L,51927L,
94210 51928L,51929L,51930L,51931L,51932L,51933L,51934L,51935L,51936L,51937L,
94211 51938L,51939L,51940L,51941L,51942L,51943L,51944L,51945L,51946L,51947L,
94212 51948L,51949L,51950L,51951L,51952L,51953L,51954L,51955L,51956L,51957L,
94213 51958L,51959L,51960L,51961L,51962L,51963L,51964L,51965L,51966L,51967L,
94214 51968L,51969L,51970L,51971L,51972L,51973L,51974L,51975L,51976L,51977L,
94215 51978L,51979L,51980L,51981L,51982L,51983L,51984L,51985L,51986L,51987L,
94216 51988L,51989L,51990L,51991L,51992L,51993L,51994L,51995L,51996L,51997L,
94217 51998L,51999L,52000L,52001L,52002L,52003L,52004L,52005L,52006L,52007L,
94218 52008L,52009L,52010L,52011L,52012L,52013L,52014L,52015L,52016L,52017L,
94219 52018L,52019L,52020L,52021L,52022L,52023L,52024L,52025L,52026L,52027L,
94220 52028L,52029L,52030L,52031L,52032L,52033L,52034L,52035L,52036L,52037L,
94221 52038L,52039L,52040L,52041L,52042L,52043L,52044L,52045L,52046L,52047L,
94222 52048L,52049L,52050L,52051L,52052L,52053L,52054L,52055L,52056L,52057L,
94223 52058L,52059L,52060L,52061L,52062L,52063L,52064L,52065L,52066L,52067L,
94224 52068L,52069L,52070L,52071L,52072L,52073L,52074L,52075L,52076L,52077L,
94225 52078L,52079L,52080L,52081L,52082L,52083L,52084L,52085L,52086L,52087L,
94226 52088L,52089L,52090L,52091L,52092L,52093L,52094L,52095L,52096L,52097L,
94227 52098L,52099L,52100L,52101L,52102L,52103L,52104L,52105L,52106L,52107L,
94228 52108L,52109L,52110L,52111L,52112L,52113L,52114L,52115L,52116L,52117L,
94229 52118L,52119L,52120L,52121L,52122L,52123L,52124L,52125L,52126L,52127L,
94230 52128L,52129L,52130L,52131L,52132L,52133L,52134L,52135L,52136L,52137L,
94231 52138L,52139L,52140L,52141L,52142L,52143L,52144L,52145L,52146L,52147L,
94232 52148L,52149L,52150L,52151L,52152L,52153L,52154L,52155L,52156L,52157L,
94233 52158L,52159L,52160L,52161L,52162L,52163L,52164L,52165L,52166L,52167L,
94234 52168L,52169L,52170L,52171L,52172L,52173L,52174L,52175L,52176L,52177L,
94235 52178L,52179L,52180L,52181L,52182L,52183L,52184L,52185L,52186L,52187L,
94236 52188L,52189L,52190L,52191L,52192L,52193L,52194L,52195L,52196L,52197L,
94237 52198L,52199L,52200L,52201L,52202L,52203L,52204L,52205L,52206L,52207L,
94238 52208L,52209L,52210L,52211L,52212L,52213L,52214L,52215L,52216L,52217L,
94239 52218L,52219L,52220L,52221L,52222L,52223L,52224L,52225L,52226L,52227L,
94240 52228L,52229L,52230L,52231L,52232L,52233L,52234L,52235L,52236L,52237L,
94241 52238L,52239L,52240L,52241L,52242L,52243L,52244L,52245L,52246L,52247L,
94242 52248L,52249L,52250L,52251L,52252L,52253L,52254L,52255L,52256L,52257L,
94243 52258L,52259L,52260L,52261L,52262L,52263L,52264L,52265L,52266L,52267L,
94244 52268L,52269L,52270L,52271L,52272L,52273L,52274L,52275L,52276L,52277L,
94245 52278L,52279L,52280L,52281L,52282L,52283L,52284L,52285L,52286L,52287L,
94246 52288L,52289L,52290L,52291L,52292L,52293L,52294L,52295L,52296L,52297L,
94247 52298L,52299L,52300L,52301L,52302L,52303L,52304L,52305L,52306L,52307L,
94248 52308L,52309L,52310L,52311L,52312L,52313L,52314L,52315L,52316L,52317L,
94249 52318L,52319L,52320L,52321L,52322L,52323L,52324L,52325L,52326L,52327L,
94250 52328L,52329L,52330L,52331L,52332L,52333L,52334L,52335L,52336L,52337L,
94251 52338L,52339L,52340L,52341L,52342L,52343L,52344L,52345L,52346L,52347L,
94252 52348L,52349L,52350L,52351L,52352L,52353L,52354L,52355L,52356L,52357L,
94253 52358L,52359L,52360L,52361L,52362L,52363L,52364L,52365L,52366L,52367L,
94254 52368L,52369L,52370L,52371L,52372L,52373L,52374L,52375L,52376L,52377L,
94255 52378L,52379L,52380L,52381L,52382L,52383L,52384L,52385L,52386L,52387L,
94256 52388L,52389L,52390L,52391L,52392L,52393L,52394L,52395L,52396L,52397L,
94257 52398L,52399L,52400L,52401L,52402L,52403L,52404L,52405L,52406L,52407L,
94258 52408L,52409L,52410L,52411L,52412L,52413L,52414L,52415L,52416L,52417L,
94259 52418L,52419L,52420L,52421L,52422L,52423L,52424L,52425L,52426L,52427L,
94260 52428L,52429L,52430L,52431L,52432L,52433L,52434L,52435L,52436L,52437L,
94261 52438L,52439L,52440L,52441L,52442L,52443L,52444L,52445L,52446L,52447L,
94262 52448L,52449L,52450L,52451L,52452L,52453L,52454L,52455L,52456L,52457L,
94263 52458L,52459L,52460L,52461L,52462L,52463L,52464L,52465L,52466L,52467L,
94264 52468L,52469L,52470L,52471L,52472L,52473L,52474L,52475L,52476L,52477L,
94265 52478L,52479L,52480L,52481L,52482L,52483L,52484L,52485L,52486L,52487L,
94266 52488L,52489L,52490L,52491L,52492L,52493L,52494L,52495L,52496L,52497L,
94267 52498L,52499L,52500L,52501L,52502L,52503L,52504L,52505L,52506L,52507L,
94268 52508L,52509L,52510L,52511L,52512L,52513L,52514L,52515L,52516L,52517L,
94269 52518L,52519L,52520L,52521L,52522L,52523L,52524L,52525L,52526L,52527L,
94270 52528L,52529L,52530L,52531L,52532L,52533L,52534L,52535L,52536L,52537L,
94271 52538L,52539L,52540L,52541L,52542L,52543L,52544L,52545L,52546L,52547L,
94272 52548L,52549L,52550L,52551L,52552L,52553L,52554L,52555L,52556L,52557L,
94273 52558L,52559L,52560L,52561L,52562L,52563L,52564L,52565L,52566L,52567L,
94274 52568L,52569L,52570L,52571L,52572L,52573L,52574L,52575L,52576L,52577L,
94275 52578L,52579L,52580L,52581L,52582L,52583L,52584L,52585L,52586L,52587L,
94276 52588L,52589L,52590L,52591L,52592L,52593L,52594L,52595L,52596L,52597L,
94277 52598L,52599L,52600L,52601L,52602L,52603L,52604L,52605L,52606L,52607L,
94278 52608L,52609L,52610L,52611L,52612L,52613L,52614L,52615L,52616L,52617L,
94279 52618L,52619L,52620L,52621L,52622L,52623L,52624L,52625L,52626L,52627L,
94280 52628L,52629L,52630L,52631L,52632L,52633L,52634L,52635L,52636L,52637L,
94281 52638L,52639L,52640L,52641L,52642L,52643L,52644L,52645L,52646L,52647L,
94282 52648L,52649L,52650L,52651L,52652L,52653L,52654L,52655L,52656L,52657L,
94283 52658L,52659L,52660L,52661L,52662L,52663L,52664L,52665L,52666L,52667L,
94284 52668L,52669L,52670L,52671L,52672L,52673L,52674L,52675L,52676L,52677L,
94285 52678L,52679L,52680L,52681L,52682L,52683L,52684L,52685L,52686L,52687L,
94286 52688L,52689L,52690L,52691L,52692L,52693L,52694L,52695L,52696L,52697L,
94287 52698L,52699L,52700L,52701L,52702L,52703L,52704L,52705L,52706L,52707L,
94288 52708L,52709L,52710L,52711L,52712L,52713L,52714L,52715L,52716L,52717L,
94289 52718L,52719L,52720L,52721L,52722L,52723L,52724L,52725L,52726L,52727L,
94290 52728L,52729L,52730L,52731L,52732L,52733L,52734L,52735L,52736L,52737L,
94291 52738L,52739L,52740L,52741L,52742L,52743L,52744L,52745L,52746L,52747L,
94292 52748L,52749L,52750L,52751L,52752L,52753L,52754L,52755L,52756L,52757L,
94293 52758L,52759L,52760L,52761L,52762L,52763L,52764L,52765L,52766L,52767L,
94294 52768L,52769L,52770L,52771L,52772L,52773L,52774L,52775L,52776L,52777L,
94295 52778L,52779L,52780L,52781L,52782L,52783L,52784L,52785L,52786L,52787L,
94296 52788L,52789L,52790L,52791L,52792L,52793L,52794L,52795L,52796L,52797L,
94297 52798L,52799L,52800L,52801L,52802L,52803L,52804L,52805L,52806L,52807L,
94298 52808L,52809L,52810L,52811L,52812L,52813L,52814L,52815L,52816L,52817L,
94299 52818L,52819L,52820L,52821L,52822L,52823L,52824L,52825L,52826L,52827L,
94300 52828L,52829L,52830L,52831L,52832L,52833L,52834L,52835L,52836L,52837L,
94301 52838L,52839L,52840L,52841L,52842L,52843L,52844L,52845L,52846L,52847L,
94302 52848L,52849L,52850L,52851L,52852L,52853L,52854L,52855L,52856L,52857L,
94303 52858L,52859L,52860L,52861L,52862L,52863L,52864L,52865L,52866L,52867L,
94304 52868L,52869L,52870L,52871L,52872L,52873L,52874L,52875L,52876L,52877L,
94305 52878L,52879L,52880L,52881L,52882L,52883L,52884L,52885L,52886L,52887L,
94306 52888L,52889L,52890L,52891L,52892L,52893L,52894L,52895L,52896L,52897L,
94307 52898L,52899L,52900L,52901L,52902L,52903L,52904L,52905L,52906L,52907L,
94308 52908L,52909L,52910L,52911L,52912L,52913L,52914L,52915L,52916L,52917L,
94309 52918L,52919L,52920L,52921L,52922L,52923L,52924L,52925L,52926L,52927L,
94310 52928L,52929L,52930L,52931L,52932L,52933L,52934L,52935L,52936L,52937L,
94311 52938L,52939L,52940L,52941L,52942L,52943L,52944L,52945L,52946L,52947L,
94312 52948L,52949L,52950L,52951L,52952L,52953L,52954L,52955L,52956L,52957L,
94313 52958L,52959L,52960L,52961L,52962L,52963L,52964L,52965L,52966L,52967L,
94314 52968L,52969L,52970L,52971L,52972L,52973L,52974L,52975L,52976L,52977L,
94315 52978L,52979L,52980L,52981L,52982L,52983L,52984L,52985L,52986L,52987L,
94316 52988L,52989L,52990L,52991L,52992L,52993L,52994L,52995L,52996L,52997L,
94317 52998L,52999L,53000L,53001L,53002L,53003L,53004L,53005L,53006L,53007L,
94318 53008L,53009L,53010L,53011L,53012L,53013L,53014L,53015L,53016L,53017L,
94319 53018L,53019L,53020L,53021L,53022L,53023L,53024L,53025L,53026L,53027L,
94320 53028L,53029L,53030L,53031L,53032L,53033L,53034L,53035L,53036L,53037L,
94321 53038L,53039L,53040L,53041L,53042L,53043L,53044L,53045L,53046L,53047L,
94322 53048L,53049L,53050L,53051L,53052L,53053L,53054L,53055L,53056L,53057L,
94323 53058L,53059L,53060L,53061L,53062L,53063L,53064L,53065L,53066L,53067L,
94324 53068L,53069L,53070L,53071L,53072L,53073L,53074L,53075L,53076L,53077L,
94325 53078L,53079L,53080L,53081L,53082L,53083L,53084L,53085L,53086L,53087L,
94326 53088L,53089L,53090L,53091L,53092L,53093L,53094L,53095L,53096L,53097L,
94327 53098L,53099L,53100L,53101L,53102L,53103L,53104L,53105L,53106L,53107L,
94328 53108L,53109L,53110L,53111L,53112L,53113L,53114L,53115L,53116L,53117L,
94329 53118L,53119L,53120L,53121L,53122L,53123L,53124L,53125L,53126L,53127L,
94330 53128L,53129L,53130L,53131L,53132L,53133L,53134L,53135L,53136L,53137L,
94331 53138L,53139L,53140L,53141L,53142L,53143L,53144L,53145L,53146L,53147L,
94332 53148L,53149L,53150L,53151L,53152L,53153L,53154L,53155L,53156L,53157L,
94333 53158L,53159L,53160L,53161L,53162L,53163L,53164L,53165L,53166L,53167L,
94334 53168L,53169L,53170L,53171L,53172L,53173L,53174L,53175L,53176L,53177L,
94335 53178L,53179L,53180L,53181L,53182L,53183L,53184L,53185L,53186L,53187L,
94336 53188L,53189L,53190L,53191L,53192L,53193L,53194L,53195L,53196L,53197L,
94337 53198L,53199L,53200L,53201L,53202L,53203L,53204L,53205L,53206L,53207L,
94338 53208L,53209L,53210L,53211L,53212L,53213L,53214L,53215L,53216L,53217L,
94339 53218L,53219L,53220L,53221L,53222L,53223L,53224L,53225L,53226L,53227L,
94340 53228L,53229L,53230L,53231L,53232L,53233L,53234L,53235L,53236L,53237L,
94341 53238L,53239L,53240L,53241L,53242L,53243L,53244L,53245L,53246L,53247L,
94342 53248L,53249L,53250L,53251L,53252L,53253L,53254L,53255L,53256L,53257L,
94343 53258L,53259L,53260L,53261L,53262L,53263L,53264L,53265L,53266L,53267L,
94344 53268L,53269L,53270L,53271L,53272L,53273L,53274L,53275L,53276L,53277L,
94345 53278L,53279L,53280L,53281L,53282L,53283L,53284L,53285L,53286L,53287L,
94346 53288L,53289L,53290L,53291L,53292L,53293L,53294L,53295L,53296L,53297L,
94347 53298L,53299L,53300L,53301L,53302L,53303L,53304L,53305L,53306L,53307L,
94348 53308L,53309L,53310L,53311L,53312L,53313L,53314L,53315L,53316L,53317L,
94349 53318L,53319L,53320L,53321L,53322L,53323L,53324L,53325L,53326L,53327L,
94350 53328L,53329L,53330L,53331L,53332L,53333L,53334L,53335L,53336L,53337L,
94351 53338L,53339L,53340L,53341L,53342L,53343L,53344L,53345L,53346L,53347L,
94352 53348L,53349L,53350L,53351L,53352L,53353L,53354L,53355L,53356L,53357L,
94353 53358L,53359L,53360L,53361L,53362L,53363L,53364L,53365L,53366L,53367L,
94354 53368L,53369L,53370L,53371L,53372L,53373L,53374L,53375L,53376L,53377L,
94355 53378L,53379L,53380L,53381L,53382L,53383L,53384L,53385L,53386L,53387L,
94356 53388L,53389L,53390L,53391L,53392L,53393L,53394L,53395L,53396L,53397L,
94357 53398L,53399L,53400L,53401L,53402L,53403L,53404L,53405L,53406L,53407L,
94358 53408L,53409L,53410L,53411L,53412L,53413L,53414L,53415L,53416L,53417L,
94359 53418L,53419L,53420L,53421L,53422L,53423L,53424L,53425L,53426L,53427L,
94360 53428L,53429L,53430L,53431L,53432L,53433L,53434L,53435L,53436L,53437L,
94361 53438L,53439L,53440L,53441L,53442L,53443L,53444L,53445L,53446L,53447L,
94362 53448L,53449L,53450L,53451L,53452L,53453L,53454L,53455L,53456L,53457L,
94363 53458L,53459L,53460L,53461L,53462L,53463L,53464L,53465L,53466L,53467L,
94364 53468L,53469L,53470L,53471L,53472L,53473L,53474L,53475L,53476L,53477L,
94365 53478L,53479L,53480L,53481L,53482L,53483L,53484L,53485L,53486L,53487L,
94366 53488L,53489L,53490L,53491L,53492L,53493L,53494L,53495L,53496L,53497L,
94367 53498L,53499L,53500L,53501L,53502L,53503L,53504L,53505L,53506L,53507L,
94368 53508L,53509L,53510L,53511L,53512L,53513L,53514L,53515L,53516L,53517L,
94369 53518L,53519L,53520L,53521L,53522L,53523L,53524L,53525L,53526L,53527L,
94370 53528L,53529L,53530L,53531L,53532L,53533L,53534L,53535L,53536L,53537L,
94371 53538L,53539L,53540L,53541L,53542L,53543L,53544L,53545L,53546L,53547L,
94372 53548L,53549L,53550L,53551L,53552L,53553L,53554L,53555L,53556L,53557L,
94373 53558L,53559L,53560L,53561L,53562L,53563L,53564L,53565L,53566L,53567L,
94374 53568L,53569L,53570L,53571L,53572L,53573L,53574L,53575L,53576L,53577L,
94375 53578L,53579L,53580L,53581L,53582L,53583L,53584L,53585L,53586L,53587L,
94376 53588L,53589L,53590L,53591L,53592L,53593L,53594L,53595L,53596L,53597L,
94377 53598L,53599L,53600L,53601L,53602L,53603L,53604L,53605L,53606L,53607L,
94378 53608L,53609L,53610L,53611L,53612L,53613L,53614L,53615L,53616L,53617L,
94379 53618L,53619L,53620L,53621L,53622L,53623L,53624L,53625L,53626L,53627L,
94380 53628L,53629L,53630L,53631L,53632L,53633L,53634L,53635L,53636L,53637L,
94381 53638L,53639L,53640L,53641L,53642L,53643L,53644L,53645L,53646L,53647L,
94382 53648L,53649L,53650L,53651L,53652L,53653L,53654L,53655L,53656L,53657L,
94383 53658L,53659L,53660L,53661L,53662L,53663L,53664L,53665L,53666L,53667L,
94384 53668L,53669L,53670L,53671L,53672L,53673L,53674L,53675L,53676L,53677L,
94385 53678L,53679L,53680L,53681L,53682L,53683L,53684L,53685L,53686L,53687L,
94386 53688L,53689L,53690L,53691L,53692L,53693L,53694L,53695L,53696L,53697L,
94387 53698L,53699L,53700L,53701L,53702L,53703L,53704L,53705L,53706L,53707L,
94388 53708L,53709L,53710L,53711L,53712L,53713L,53714L,53715L,53716L,53717L,
94389 53718L,53719L,53720L,53721L,53722L,53723L,53724L,53725L,53726L,53727L,
94390 53728L,53729L,53730L,53731L,53732L,53733L,53734L,53735L,53736L,53737L,
94391 53738L,53739L,53740L,53741L,53742L,53743L,53744L,53745L,53746L,53747L,
94392 53748L,53749L,53750L,53751L,53752L,53753L,53754L,53755L,53756L,53757L,
94393 53758L,53759L,53760L,53761L,53762L,53763L,53764L,53765L,53766L,53767L,
94394 53768L,53769L,53770L,53771L,53772L,53773L,53774L,53775L,53776L,53777L,
94395 53778L,53779L,53780L,53781L,53782L,53783L,53784L,53785L,53786L,53787L,
94396 53788L,53789L,53790L,53791L,53792L,53793L,53794L,53795L,53796L,53797L,
94397 53798L,53799L,53800L,53801L,53802L,53803L,53804L,53805L,53806L,53807L,
94398 53808L,53809L,53810L,53811L,53812L,53813L,53814L,53815L,53816L,53817L,
94399 53818L,53819L,53820L,53821L,53822L,53823L,53824L,53825L,53826L,53827L,
94400 53828L,53829L,53830L,53831L,53832L,53833L,53834L,53835L,53836L,53837L,
94401 53838L,53839L,53840L,53841L,53842L,53843L,53844L,53845L,53846L,53847L,
94402 53848L,53849L,53850L,53851L,53852L,53853L,53854L,53855L,53856L,53857L,
94403 53858L,53859L,53860L,53861L,53862L,53863L,53864L,53865L,53866L,53867L,
94404 53868L,53869L,53870L,53871L,53872L,53873L,53874L,53875L,53876L,53877L,
94405 53878L,53879L,53880L,53881L,53882L,53883L,53884L,53885L,53886L,53887L,
94406 53888L,53889L,53890L,53891L,53892L,53893L,53894L,53895L,53896L,53897L,
94407 53898L,53899L,53900L,53901L,53902L,53903L,53904L,53905L,53906L,53907L,
94408 53908L,53909L,53910L,53911L,53912L,53913L,53914L,53915L,53916L,53917L,
94409 53918L,53919L,53920L,53921L,53922L,53923L,53924L,53925L,53926L,53927L,
94410 53928L,53929L,53930L,53931L,53932L,53933L,53934L,53935L,53936L,53937L,
94411 53938L,53939L,53940L,53941L,53942L,53943L,53944L,53945L,53946L,53947L,
94412 53948L,53949L,53950L,53951L,53952L,53953L,53954L,53955L,53956L,53957L,
94413 53958L,53959L,53960L,53961L,53962L,53963L,53964L,53965L,53966L,53967L,
94414 53968L,53969L,53970L,53971L,53972L,53973L,53974L,53975L,53976L,53977L,
94415 53978L,53979L,53980L,53981L,53982L,53983L,53984L,53985L,53986L,53987L,
94416 53988L,53989L,53990L,53991L,53992L,53993L,53994L,53995L,53996L,53997L,
94417 53998L,53999L,54000L,54001L,54002L,54003L,54004L,54005L,54006L,54007L,
94418 54008L,54009L,54010L,54011L,54012L,54013L,54014L,54015L,54016L,54017L,
94419 54018L,54019L,54020L,54021L,54022L,54023L,54024L,54025L,54026L,54027L,
94420 54028L,54029L,54030L,54031L,54032L,54033L,54034L,54035L,54036L,54037L,
94421 54038L,54039L,54040L,54041L,54042L,54043L,54044L,54045L,54046L,54047L,
94422 54048L,54049L,54050L,54051L,54052L,54053L,54054L,54055L,54056L,54057L,
94423 54058L,54059L,54060L,54061L,54062L,54063L,54064L,54065L,54066L,54067L,
94424 54068L,54069L,54070L,54071L,54072L,54073L,54074L,54075L,54076L,54077L,
94425 54078L,54079L,54080L,54081L,54082L,54083L,54084L,54085L,54086L,54087L,
94426 54088L,54089L,54090L,54091L,54092L,54093L,54094L,54095L,54096L,54097L,
94427 54098L,54099L,54100L,54101L,54102L,54103L,54104L,54105L,54106L,54107L,
94428 54108L,54109L,54110L,54111L,54112L,54113L,54114L,54115L,54116L,54117L,
94429 54118L,54119L,54120L,54121L,54122L,54123L,54124L,54125L,54126L,54127L,
94430 54128L,54129L,54130L,54131L,54132L,54133L,54134L,54135L,54136L,54137L,
94431 54138L,54139L,54140L,54141L,54142L,54143L,54144L,54145L,54146L,54147L,
94432 54148L,54149L,54150L,54151L,54152L,54153L,54154L,54155L,54156L,54157L,
94433 54158L,54159L,54160L,54161L,54162L,54163L,54164L,54165L,54166L,54167L,
94434 54168L,54169L,54170L,54171L,54172L,54173L,54174L,54175L,54176L,54177L,
94435 54178L,54179L,54180L,54181L,54182L,54183L,54184L,54185L,54186L,54187L,
94436 54188L,54189L,54190L,54191L,54192L,54193L,54194L,54195L,54196L,54197L,
94437 54198L,54199L,54200L,54201L,54202L,54203L,54204L,54205L,54206L,54207L,
94438 54208L,54209L,54210L,54211L,54212L,54213L,54214L,54215L,54216L,54217L,
94439 54218L,54219L,54220L,54221L,54222L,54223L,54224L,54225L,54226L,54227L,
94440 54228L,54229L,54230L,54231L,54232L,54233L,54234L,54235L,54236L,54237L,
94441 54238L,54239L,54240L,54241L,54242L,54243L,54244L,54245L,54246L,54247L,
94442 54248L,54249L,54250L,54251L,54252L,54253L,54254L,54255L,54256L,54257L,
94443 54258L,54259L,54260L,54261L,54262L,54263L,54264L,54265L,54266L,54267L,
94444 54268L,54269L,54270L,54271L,54272L,54273L,54274L,54275L,54276L,54277L,
94445 54278L,54279L,54280L,54281L,54282L,54283L,54284L,54285L,54286L,54287L,
94446 54288L,54289L,54290L,54291L,54292L,54293L,54294L,54295L,54296L,54297L,
94447 54298L,54299L,54300L,54301L,54302L,54303L,54304L,54305L,54306L,54307L,
94448 54308L,54309L,54310L,54311L,54312L,54313L,54314L,54315L,54316L,54317L,
94449 54318L,54319L,54320L,54321L,54322L,54323L,54324L,54325L,54326L,54327L,
94450 54328L,54329L,54330L,54331L,54332L,54333L,54334L,54335L,54336L,54337L,
94451 54338L,54339L,54340L,54341L,54342L,54343L,54344L,54345L,54346L,54347L,
94452 54348L,54349L,54350L,54351L,54352L,54353L,54354L,54355L,54356L,54357L,
94453 54358L,54359L,54360L,54361L,54362L,54363L,54364L,54365L,54366L,54367L,
94454 54368L,54369L,54370L,54371L,54372L,54373L,54374L,54375L,54376L,54377L,
94455 54378L,54379L,54380L,54381L,54382L,54383L,54384L,54385L,54386L,54387L,
94456 54388L,54389L,54390L,54391L,54392L,54393L,54394L,54395L,54396L,54397L,
94457 54398L,54399L,54400L,54401L,54402L,54403L,54404L,54405L,54406L,54407L,
94458 54408L,54409L,54410L,54411L,54412L,54413L,54414L,54415L,54416L,54417L,
94459 54418L,54419L,54420L,54421L,54422L,54423L,54424L,54425L,54426L,54427L,
94460 54428L,54429L,54430L,54431L,54432L,54433L,54434L,54435L,54436L,54437L,
94461 54438L,54439L,54440L,54441L,54442L,54443L,54444L,54445L,54446L,54447L,
94462 54448L,54449L,54450L,54451L,54452L,54453L,54454L,54455L,54456L,54457L,
94463 54458L,54459L,54460L,54461L,54462L,54463L,54464L,54465L,54466L,54467L,
94464 54468L,54469L,54470L,54471L,54472L,54473L,54474L,54475L,54476L,54477L,
94465 54478L,54479L,54480L,54481L,54482L,54483L,54484L,54485L,54486L,54487L,
94466 54488L,54489L,54490L,54491L,54492L,54493L,54494L,54495L,54496L,54497L,
94467 54498L,54499L,54500L,54501L,54502L,54503L,54504L,54505L,54506L,54507L,
94468 54508L,54509L,54510L,54511L,54512L,54513L,54514L,54515L,54516L,54517L,
94469 54518L,54519L,54520L,54521L,54522L,54523L,54524L,54525L,54526L,54527L,
94470 54528L,54529L,54530L,54531L,54532L,54533L,54534L,54535L,54536L,54537L,
94471 54538L,54539L,54540L,54541L,54542L,54543L,54544L,54545L,54546L,54547L,
94472 54548L,54549L,54550L,54551L,54552L,54553L,54554L,54555L,54556L,54557L,
94473 54558L,54559L,54560L,54561L,54562L,54563L,54564L,54565L,54566L,54567L,
94474 54568L,54569L,54570L,54571L,54572L,54573L,54574L,54575L,54576L,54577L,
94475 54578L,54579L,54580L,54581L,54582L,54583L,54584L,54585L,54586L,54587L,
94476 54588L,54589L,54590L,54591L,54592L,54593L,54594L,54595L,54596L,54597L,
94477 54598L,54599L,54600L,54601L,54602L,54603L,54604L,54605L,54606L,54607L,
94478 54608L,54609L,54610L,54611L,54612L,54613L,54614L,54615L,54616L,54617L,
94479 54618L,54619L,54620L,54621L,54622L,54623L,54624L,54625L,54626L,54627L,
94480 54628L,54629L,54630L,54631L,54632L,54633L,54634L,54635L,54636L,54637L,
94481 54638L,54639L,54640L,54641L,54642L,54643L,54644L,54645L,54646L,54647L,
94482 54648L,54649L,54650L,54651L,54652L,54653L,54654L,54655L,54656L,54657L,
94483 54658L,54659L,54660L,54661L,54662L,54663L,54664L,54665L,54666L,54667L,
94484 54668L,54669L,54670L,54671L,54672L,54673L,54674L,54675L,54676L,54677L,
94485 54678L,54679L,54680L,54681L,54682L,54683L,54684L,54685L,54686L,54687L,
94486 54688L,54689L,54690L,54691L,54692L,54693L,54694L,54695L,54696L,54697L,
94487 54698L,54699L,54700L,54701L,54702L,54703L,54704L,54705L,54706L,54707L,
94488 54708L,54709L,54710L,54711L,54712L,54713L,54714L,54715L,54716L,54717L,
94489 54718L,54719L,54720L,54721L,54722L,54723L,54724L,54725L,54726L,54727L,
94490 54728L,54729L,54730L,54731L,54732L,54733L,54734L,54735L,54736L,54737L,
94491 54738L,54739L,54740L,54741L,54742L,54743L,54744L,54745L,54746L,54747L,
94492 54748L,54749L,54750L,54751L,54752L,54753L,54754L,54755L,54756L,54757L,
94493 54758L,54759L,54760L,54761L,54762L,54763L,54764L,54765L,54766L,54767L,
94494 54768L,54769L,54770L,54771L,54772L,54773L,54774L,54775L,54776L,54777L,
94495 54778L,54779L,54780L,54781L,54782L,54783L,54784L,54785L,54786L,54787L,
94496 54788L,54789L,54790L,54791L,54792L,54793L,54794L,54795L,54796L,54797L,
94497 54798L,54799L,54800L,54801L,54802L,54803L,54804L,54805L,54806L,54807L,
94498 54808L,54809L,54810L,54811L,54812L,54813L,54814L,54815L,54816L,54817L,
94499 54818L,54819L,54820L,54821L,54822L,54823L,54824L,54825L,54826L,54827L,
94500 54828L,54829L,54830L,54831L,54832L,54833L,54834L,54835L,54836L,54837L,
94501 54838L,54839L,54840L,54841L,54842L,54843L,54844L,54845L,54846L,54847L,
94502 54848L,54849L,54850L,54851L,54852L,54853L,54854L,54855L,54856L,54857L,
94503 54858L,54859L,54860L,54861L,54862L,54863L,54864L,54865L,54866L,54867L,
94504 54868L,54869L,54870L,54871L,54872L,54873L,54874L,54875L,54876L,54877L,
94505 54878L,54879L,54880L,54881L,54882L,54883L,54884L,54885L,54886L,54887L,
94506 54888L,54889L,54890L,54891L,54892L,54893L,54894L,54895L,54896L,54897L,
94507 54898L,54899L,54900L,54901L,54902L,54903L,54904L,54905L,54906L,54907L,
94508 54908L,54909L,54910L,54911L,54912L,54913L,54914L,54915L,54916L,54917L,
94509 54918L,54919L,54920L,54921L,54922L,54923L,54924L,54925L,54926L,54927L,
94510 54928L,54929L,54930L,54931L,54932L,54933L,54934L,54935L,54936L,54937L,
94511 54938L,54939L,54940L,54941L,54942L,54943L,54944L,54945L,54946L,54947L,
94512 54948L,54949L,54950L,54951L,54952L,54953L,54954L,54955L,54956L,54957L,
94513 54958L,54959L,54960L,54961L,54962L,54963L,54964L,54965L,54966L,54967L,
94514 54968L,54969L,54970L,54971L,54972L,54973L,54974L,54975L,54976L,54977L,
94515 54978L,54979L,54980L,54981L,54982L,54983L,54984L,54985L,54986L,54987L,
94516 54988L,54989L,54990L,54991L,54992L,54993L,54994L,54995L,54996L,54997L,
94517 54998L,54999L,55000L,55001L,55002L,55003L,55004L,55005L,55006L,55007L,
94518 55008L,55009L,55010L,55011L,55012L,55013L,55014L,55015L,55016L,55017L,
94519 55018L,55019L,55020L,55021L,55022L,55023L,55024L,55025L,55026L,55027L,
94520 55028L,55029L,55030L,55031L,55032L,55033L,55034L,55035L,55036L,55037L,
94521 55038L,55039L,55040L,55041L,55042L,55043L,55044L,55045L,55046L,55047L,
94522 55048L,55049L,55050L,55051L,55052L,55053L,55054L,55055L,55056L,55057L,
94523 55058L,55059L,55060L,55061L,55062L,55063L,55064L,55065L,55066L,55067L,
94524 55068L,55069L,55070L,55071L,55072L,55073L,55074L,55075L,55076L,55077L,
94525 55078L,55079L,55080L,55081L,55082L,55083L,55084L,55085L,55086L,55087L,
94526 55088L,55089L,55090L,55091L,55092L,55093L,55094L,55095L,55096L,55097L,
94527 55098L,55099L,55100L,55101L,55102L,55103L,55104L,55105L,55106L,55107L,
94528 55108L,55109L,55110L,55111L,55112L,55113L,55114L,55115L,55116L,55117L,
94529 55118L,55119L,55120L,55121L,55122L,55123L,55124L,55125L,55126L,55127L,
94530 55128L,55129L,55130L,55131L,55132L,55133L,55134L,55135L,55136L,55137L,
94531 55138L,55139L,55140L,55141L,55142L,55143L,55144L,55145L,55146L,55147L,
94532 55148L,55149L,55150L,55151L,55152L,55153L,55154L,55155L,55156L,55157L,
94533 55158L,55159L,55160L,55161L,55162L,55163L,55164L,55165L,55166L,55167L,
94534 55168L,55169L,55170L,55171L,55172L,55173L,55174L,55175L,55176L,55177L,
94535 55178L,55179L,55180L,55181L,55182L,55183L,55184L,55185L,55186L,55187L,
94536 55188L,55189L,55190L,55191L,55192L,55193L,55194L,55195L,55196L,55197L,
94537 55198L,55199L,55200L,55201L,55202L,55203L,55204L,55205L,55206L,55207L,
94538 55208L,55209L,55210L,55211L,55212L,55213L,55214L,55215L,55216L,55217L,
94539 55218L,55219L,55220L,55221L,55222L,55223L,55224L,55225L,55226L,55227L,
94540 55228L,55229L,55230L,55231L,55232L,55233L,55234L,55235L,55236L,55237L,
94541 55238L,55239L,55240L,55241L,55242L,55243L,55244L,55245L,55246L,55247L,
94542 55248L,55249L,55250L,55251L,55252L,55253L,55254L,55255L,55256L,55257L,
94543 55258L,55259L,55260L,55261L,55262L,55263L,55264L,55265L,55266L,55267L,
94544 55268L,55269L,55270L,55271L,55272L,55273L,55274L,55275L,55276L,55277L,
94545 55278L,55279L,55280L,55281L,55282L,55283L,55284L,55285L,55286L,55287L,
94546 55288L,55289L,55290L,55291L,55292L,55293L,55294L,55295L,55296L,55297L,
94547 55298L,55299L,55300L,55301L,55302L,55303L,55304L,55305L,55306L,55307L,
94548 55308L,55309L,55310L,55311L,55312L,55313L,55314L,55315L,55316L,55317L,
94549 55318L,55319L,55320L,55321L,55322L,55323L,55324L,55325L,55326L,55327L,
94550 55328L,55329L,55330L,55331L,55332L,55333L,55334L,55335L,55336L,55337L,
94551 55338L,55339L,55340L,55341L,55342L,55343L,55344L,55345L,55346L,55347L,
94552 55348L,55349L,55350L,55351L,55352L,55353L,55354L,55355L,55356L,55357L,
94553 55358L,55359L,55360L,55361L,55362L,55363L,55364L,55365L,55366L,55367L,
94554 55368L,55369L,55370L,55371L,55372L,55373L,55374L,55375L,55376L,55377L,
94555 55378L,55379L,55380L,55381L,55382L,55383L,55384L,55385L,55386L,55387L,
94556 55388L,55389L,55390L,55391L,55392L,55393L,55394L,55395L,55396L,55397L,
94557 55398L,55399L,55400L,55401L,55402L,55403L,55404L,55405L,55406L,55407L,
94558 55408L,55409L,55410L,55411L,55412L,55413L,55414L,55415L,55416L,55417L,
94559 55418L,55419L,55420L,55421L,55422L,55423L,55424L,55425L,55426L,55427L,
94560 55428L,55429L,55430L,55431L,55432L,55433L,55434L,55435L,55436L,55437L,
94561 55438L,55439L,55440L,55441L,55442L,55443L,55444L,55445L,55446L,55447L,
94562 55448L,55449L,55450L,55451L,55452L,55453L,55454L,55455L,55456L,55457L,
94563 55458L,55459L,55460L,55461L,55462L,55463L,55464L,55465L,55466L,55467L,
94564 55468L,55469L,55470L,55471L,55472L,55473L,55474L,55475L,55476L,55477L,
94565 55478L,55479L,55480L,55481L,55482L,55483L,55484L,55485L,55486L,55487L,
94566 55488L,55489L,55490L,55491L,55492L,55493L,55494L,55495L,55496L,55497L,
94567 55498L,55499L,55500L,55501L,55502L,55503L,55504L,55505L,55506L,55507L,
94568 55508L,55509L,55510L,55511L,55512L,55513L,55514L,55515L,55516L,55517L,
94569 55518L,55519L,55520L,55521L,55522L,55523L,55524L,55525L,55526L,55527L,
94570 55528L,55529L,55530L,55531L,55532L,55533L,55534L,55535L,55536L,55537L,
94571 55538L,55539L,55540L,55541L,55542L,55543L,55544L,55545L,55546L,55547L,
94572 55548L,55549L,55550L,55551L,55552L,55553L,55554L,55555L,55556L,55557L,
94573 55558L,55559L,55560L,55561L,55562L,55563L,55564L,55565L,55566L,55567L,
94574 55568L,55569L,55570L,55571L,55572L,55573L,55574L,55575L,55576L,55577L,
94575 55578L,55579L,55580L,55581L,55582L,55583L,55584L,55585L,55586L,55587L,
94576 55588L,55589L,55590L,55591L,55592L,55593L,55594L,55595L,55596L,55597L,
94577 55598L,55599L,55600L,55601L,55602L,55603L,55604L,55605L,55606L,55607L,
94578 55608L,55609L,55610L,55611L,55612L,55613L,55614L,55615L,55616L,55617L,
94579 55618L,55619L,55620L,55621L,55622L,55623L,55624L,55625L,55626L,55627L,
94580 55628L,55629L,55630L,55631L,55632L,55633L,55634L,55635L,55636L,55637L,
94581 55638L,55639L,55640L,55641L,55642L,55643L,55644L,55645L,55646L,55647L,
94582 55648L,55649L,55650L,55651L,55652L,55653L,55654L,55655L,55656L,55657L,
94583 55658L,55659L,55660L,55661L,55662L,55663L,55664L,55665L,55666L,55667L,
94584 55668L,55669L,55670L,55671L,55672L,55673L,55674L,55675L,55676L,55677L,
94585 55678L,55679L,55680L,55681L,55682L,55683L,55684L,55685L,55686L,55687L,
94586 55688L,55689L,55690L,55691L,55692L,55693L,55694L,55695L,55696L,55697L,
94587 55698L,55699L,55700L,55701L,55702L,55703L,55704L,55705L,55706L,55707L,
94588 55708L,55709L,55710L,55711L,55712L,55713L,55714L,55715L,55716L,55717L,
94589 55718L,55719L,55720L,55721L,55722L,55723L,55724L,55725L,55726L,55727L,
94590 55728L,55729L,55730L,55731L,55732L,55733L,55734L,55735L,55736L,55737L,
94591 55738L,55739L,55740L,55741L,55742L,55743L,55744L,55745L,55746L,55747L,
94592 55748L,55749L,55750L,55751L,55752L,55753L,55754L,55755L,55756L,55757L,
94593 55758L,55759L,55760L,55761L,55762L,55763L,55764L,55765L,55766L,55767L,
94594 55768L,55769L,55770L,55771L,55772L,55773L,55774L,55775L,55776L,55777L,
94595 55778L,55779L,55780L,55781L,55782L,55783L,55784L,55785L,55786L,55787L,
94596 55788L,55789L,55790L,55791L,55792L,55793L,55794L,55795L,55796L,55797L,
94597 55798L,55799L,55800L,55801L,55802L,55803L,55804L,55805L,55806L,55807L,
94598 55808L,55809L,55810L,55811L,55812L,55813L,55814L,55815L,55816L,55817L,
94599 55818L,55819L,55820L,55821L,55822L,55823L,55824L,55825L,55826L,55827L,
94600 55828L,55829L,55830L,55831L,55832L,55833L,55834L,55835L,55836L,55837L,
94601 55838L,55839L,55840L,55841L,55842L,55843L,55844L,55845L,55846L,55847L,
94602 55848L,55849L,55850L,55851L,55852L,55853L,55854L,55855L,55856L,55857L,
94603 55858L,55859L,55860L,55861L,55862L,55863L,55864L,55865L,55866L,55867L,
94604 55868L,55869L,55870L,55871L,55872L,55873L,55874L,55875L,55876L,55877L,
94605 55878L,55879L,55880L,55881L,55882L,55883L,55884L,55885L,55886L,55887L,
94606 55888L,55889L,55890L,55891L,55892L,55893L,55894L,55895L,55896L,55897L,
94607 55898L,55899L,55900L,55901L,55902L,55903L,55904L,55905L,55906L,55907L,
94608 55908L,55909L,55910L,55911L,55912L,55913L,55914L,55915L,55916L,55917L,
94609 55918L,55919L,55920L,55921L,55922L,55923L,55924L,55925L,55926L,55927L,
94610 55928L,55929L,55930L,55931L,55932L,55933L,55934L,55935L,55936L,55937L,
94611 55938L,55939L,55940L,55941L,55942L,55943L,55944L,55945L,55946L,55947L,
94612 55948L,55949L,55950L,55951L,55952L,55953L,55954L,55955L,55956L,55957L,
94613 55958L,55959L,55960L,55961L,55962L,55963L,55964L,55965L,55966L,55967L,
94614 55968L,55969L,55970L,55971L,55972L,55973L,55974L,55975L,55976L,55977L,
94615 55978L,55979L,55980L,55981L,55982L,55983L,55984L,55985L,55986L,55987L,
94616 55988L,55989L,55990L,55991L,55992L,55993L,55994L,55995L,55996L,55997L,
94617 55998L,55999L,56000L,56001L,56002L,56003L,56004L,56005L,56006L,56007L,
94618 56008L,56009L,56010L,56011L,56012L,56013L,56014L,56015L,56016L,56017L,
94619 56018L,56019L,56020L,56021L,56022L,56023L,56024L,56025L,56026L,56027L,
94620 56028L,56029L,56030L,56031L,56032L,56033L,56034L,56035L,56036L,56037L,
94621 56038L,56039L,56040L,56041L,56042L,56043L,56044L,56045L,56046L,56047L,
94622 56048L,56049L,56050L,56051L,56052L,56053L,56054L,56055L,56056L,56057L,
94623 56058L,56059L,56060L,56061L,56062L,56063L,56064L,56065L,56066L,56067L,
94624 56068L,56069L,56070L,56071L,56072L,56073L,56074L,56075L,56076L,56077L,
94625 56078L,56079L,56080L,56081L,56082L,56083L,56084L,56085L,56086L,56087L,
94626 56088L,56089L,56090L,56091L,56092L,56093L,56094L,56095L,56096L,56097L,
94627 56098L,56099L,56100L,56101L,56102L,56103L,56104L,56105L,56106L,56107L,
94628 56108L,56109L,56110L,56111L,56112L,56113L,56114L,56115L,56116L,56117L,
94629 56118L,56119L,56120L,56121L,56122L,56123L,56124L,56125L,56126L,56127L,
94630 56128L,56129L,56130L,56131L,56132L,56133L,56134L,56135L,56136L,56137L,
94631 56138L,56139L,56140L,56141L,56142L,56143L,56144L,56145L,56146L,56147L,
94632 56148L,56149L,56150L,56151L,56152L,56153L,56154L,56155L,56156L,56157L,
94633 56158L,56159L,56160L,56161L,56162L,56163L,56164L,56165L,56166L,56167L,
94634 56168L,56169L,56170L,56171L,56172L,56173L,56174L,56175L,56176L,56177L,
94635 56178L,56179L,56180L,56181L,56182L,56183L,56184L,56185L,56186L,56187L,
94636 56188L,56189L,56190L,56191L,56192L,56193L,56194L,56195L,56196L,56197L,
94637 56198L,56199L,56200L,56201L,56202L,56203L,56204L,56205L,56206L,56207L,
94638 56208L,56209L,56210L,56211L,56212L,56213L,56214L,56215L,56216L,56217L,
94639 56218L,56219L,56220L,56221L,56222L,56223L,56224L,56225L,56226L,56227L,
94640 56228L,56229L,56230L,56231L,56232L,56233L,56234L,56235L,56236L,56237L,
94641 56238L,56239L,56240L,56241L,56242L,56243L,56244L,56245L,56246L,56247L,
94642 56248L,56249L,56250L,56251L,56252L,56253L,56254L,56255L,56256L,56257L,
94643 56258L,56259L,56260L,56261L,56262L,56263L,56264L,56265L,56266L,56267L,
94644 56268L,56269L,56270L,56271L,56272L,56273L,56274L,56275L,56276L,56277L,
94645 56278L,56279L,56280L,56281L,56282L,56283L,56284L,56285L,56286L,56287L,
94646 56288L,56289L,56290L,56291L,56292L,56293L,56294L,56295L,56296L,56297L,
94647 56298L,56299L,56300L,56301L,56302L,56303L,56304L,56305L,56306L,56307L,
94648 56308L,56309L,56310L,56311L,56312L,56313L,56314L,56315L,56316L,56317L,
94649 56318L,56319L,56320L,56321L,56322L,56323L,56324L,56325L,56326L,56327L,
94650 56328L,56329L,56330L,56331L,56332L,56333L,56334L,56335L,56336L,56337L,
94651 56338L,56339L,56340L,56341L,56342L,56343L,56344L,56345L,56346L,56347L,
94652 56348L,56349L,56350L,56351L,56352L,56353L,56354L,56355L,56356L,56357L,
94653 56358L,56359L,56360L,56361L,56362L,56363L,56364L,56365L,56366L,56367L,
94654 56368L,56369L,56370L,56371L,56372L,56373L,56374L,56375L,56376L,56377L,
94655 56378L,56379L,56380L,56381L,56382L,56383L,56384L,56385L,56386L,56387L,
94656 56388L,56389L,56390L,56391L,56392L,56393L,56394L,56395L,56396L,56397L,
94657 56398L,56399L,56400L,56401L,56402L,56403L,56404L,56405L,56406L,56407L,
94658 56408L,56409L,56410L,56411L,56412L,56413L,56414L,56415L,56416L,56417L,
94659 56418L,56419L,56420L,56421L,56422L,56423L,56424L,56425L,56426L,56427L,
94660 56428L,56429L,56430L,56431L,56432L,56433L,56434L,56435L,56436L,56437L,
94661 56438L,56439L,56440L,56441L,56442L,56443L,56444L,56445L,56446L,56447L,
94662 56448L,56449L,56450L,56451L,56452L,56453L,56454L,56455L,56456L,56457L,
94663 56458L,56459L,56460L,56461L,56462L,56463L,56464L,56465L,56466L,56467L,
94664 56468L,56469L,56470L,56471L,56472L,56473L,56474L,56475L,56476L,56477L,
94665 56478L,56479L,56480L,56481L,56482L,56483L,56484L,56485L,56486L,56487L,
94666 56488L,56489L,56490L,56491L,56492L,56493L,56494L,56495L,56496L,56497L,
94667 56498L,56499L,56500L,56501L,56502L,56503L,56504L,56505L,56506L,56507L,
94668 56508L,56509L,56510L,56511L,56512L,56513L,56514L,56515L,56516L,56517L,
94669 56518L,56519L,56520L,56521L,56522L,56523L,56524L,56525L,56526L,56527L,
94670 56528L,56529L,56530L,56531L,56532L,56533L,56534L,56535L,56536L,56537L,
94671 56538L,56539L,56540L,56541L,56542L,56543L,56544L,56545L,56546L,56547L,
94672 56548L,56549L,56550L,56551L,56552L,56553L,56554L,56555L,56556L,56557L,
94673 56558L,56559L,56560L,56561L,56562L,56563L,56564L,56565L,56566L,56567L,
94674 56568L,56569L,56570L,56571L,56572L,56573L,56574L,56575L,56576L,56577L,
94675 56578L,56579L,56580L,56581L,56582L,56583L,56584L,56585L,56586L,56587L,
94676 56588L,56589L,56590L,56591L,56592L,56593L,56594L,56595L,56596L,56597L,
94677 56598L,56599L,56600L,56601L,56602L,56603L,56604L,56605L,56606L,56607L,
94678 56608L,56609L,56610L,56611L,56612L,56613L,56614L,56615L,56616L,56617L,
94679 56618L,56619L,56620L,56621L,56622L,56623L,56624L,56625L,56626L,56627L,
94680 56628L,56629L,56630L,56631L,56632L,56633L,56634L,56635L,56636L,56637L,
94681 56638L,56639L,56640L,56641L,56642L,56643L,56644L,56645L,56646L,56647L,
94682 56648L,56649L,56650L,56651L,56652L,56653L,56654L,56655L,56656L,56657L,
94683 56658L,56659L,56660L,56661L,56662L,56663L,56664L,56665L,56666L,56667L,
94684 56668L,56669L,56670L,56671L,56672L,56673L,56674L,56675L,56676L,56677L,
94685 56678L,56679L,56680L,56681L,56682L,56683L,56684L,56685L,56686L,56687L,
94686 56688L,56689L,56690L,56691L,56692L,56693L,56694L,56695L,56696L,56697L,
94687 56698L,56699L,56700L,56701L,56702L,56703L,56704L,56705L,56706L,56707L,
94688 56708L,56709L,56710L,56711L,56712L,56713L,56714L,56715L,56716L,56717L,
94689 56718L,56719L,56720L,56721L,56722L,56723L,56724L,56725L,56726L,56727L,
94690 56728L,56729L,56730L,56731L,56732L,56733L,56734L,56735L,56736L,56737L,
94691 56738L,56739L,56740L,56741L,56742L,56743L,56744L,56745L,56746L,56747L,
94692 56748L,56749L,56750L,56751L,56752L,56753L,56754L,56755L,56756L,56757L,
94693 56758L,56759L,56760L,56761L,56762L,56763L,56764L,56765L,56766L,56767L,
94694 56768L,56769L,56770L,56771L,56772L,56773L,56774L,56775L,56776L,56777L,
94695 56778L,56779L,56780L,56781L,56782L,56783L,56784L,56785L,56786L,56787L,
94696 56788L,56789L,56790L,56791L,56792L,56793L,56794L,56795L,56796L,56797L,
94697 56798L,56799L,56800L,56801L,56802L,56803L,56804L,56805L,56806L,56807L,
94698 56808L,56809L,56810L,56811L,56812L,56813L,56814L,56815L,56816L,56817L,
94699 56818L,56819L,56820L,56821L,56822L,56823L,56824L,56825L,56826L,56827L,
94700 56828L,56829L,56830L,56831L,56832L,56833L,56834L,56835L,56836L,56837L,
94701 56838L,56839L,56840L,56841L,56842L,56843L,56844L,56845L,56846L,56847L,
94702 56848L,56849L,56850L,56851L,56852L,56853L,56854L,56855L,56856L,56857L,
94703 56858L,56859L,56860L,56861L,56862L,56863L,56864L,56865L,56866L,56867L,
94704 56868L,56869L,56870L,56871L,56872L,56873L,56874L,56875L,56876L,56877L,
94705 56878L,56879L,56880L,56881L,56882L,56883L,56884L,56885L,56886L,56887L,
94706 56888L,56889L,56890L,56891L,56892L,56893L,56894L,56895L,56896L,56897L,
94707 56898L,56899L,56900L,56901L,56902L,56903L,56904L,56905L,56906L,56907L,
94708 56908L,56909L,56910L,56911L,56912L,56913L,56914L,56915L,56916L,56917L,
94709 56918L,56919L,56920L,56921L,56922L,56923L,56924L,56925L,56926L,56927L,
94710 56928L,56929L,56930L,56931L,56932L,56933L,56934L,56935L,56936L,56937L,
94711 56938L,56939L,56940L,56941L,56942L,56943L,56944L,56945L,56946L,56947L,
94712 56948L,56949L,56950L,56951L,56952L,56953L,56954L,56955L,56956L,56957L,
94713 56958L,56959L,56960L,56961L,56962L,56963L,56964L,56965L,56966L,56967L,
94714 56968L,56969L,56970L,56971L,56972L,56973L,56974L,56975L,56976L,56977L,
94715 56978L,56979L,56980L,56981L,56982L,56983L,56984L,56985L,56986L,56987L,
94716 56988L,56989L,56990L,56991L,56992L,56993L,56994L,56995L,56996L,56997L,
94717 56998L,56999L,57000L,57001L,57002L,57003L,57004L,57005L,57006L,57007L,
94718 57008L,57009L,57010L,57011L,57012L,57013L,57014L,57015L,57016L,57017L,
94719 57018L,57019L,57020L,57021L,57022L,57023L,57024L,57025L,57026L,57027L,
94720 57028L,57029L,57030L,57031L,57032L,57033L,57034L,57035L,57036L,57037L,
94721 57038L,57039L,57040L,57041L,57042L,57043L,57044L,57045L,57046L,57047L,
94722 57048L,57049L,57050L,57051L,57052L,57053L,57054L,57055L,57056L,57057L,
94723 57058L,57059L,57060L,57061L,57062L,57063L,57064L,57065L,57066L,57067L,
94724 57068L,57069L,57070L,57071L,57072L,57073L,57074L,57075L,57076L,57077L,
94725 57078L,57079L,57080L,57081L,57082L,57083L,57084L,57085L,57086L,57087L,
94726 57088L,57089L,57090L,57091L,57092L,57093L,57094L,57095L,57096L,57097L,
94727 57098L,57099L,57100L,57101L,57102L,57103L,57104L,57105L,57106L,57107L,
94728 57108L,57109L,57110L,57111L,57112L,57113L,57114L,57115L,57116L,57117L,
94729 57118L,57119L,57120L,57121L,57122L,57123L,57124L,57125L,57126L,57127L,
94730 57128L,57129L,57130L,57131L,57132L,57133L,57134L,57135L,57136L,57137L,
94731 57138L,57139L,57140L,57141L,57142L,57143L,57144L,57145L,57146L,57147L,
94732 57148L,57149L,57150L,57151L,57152L,57153L,57154L,57155L,57156L,57157L,
94733 57158L,57159L,57160L,57161L,57162L,57163L,57164L,57165L,57166L,57167L,
94734 57168L,57169L,57170L,57171L,57172L,57173L,57174L,57175L,57176L,57177L,
94735 57178L,57179L,57180L,57181L,57182L,57183L,57184L,57185L,57186L,57187L,
94736 57188L,57189L,57190L,57191L,57192L,57193L,57194L,57195L,57196L,57197L,
94737 57198L,57199L,57200L,57201L,57202L,57203L,57204L,57205L,57206L,57207L,
94738 57208L,57209L,57210L,57211L,57212L,57213L,57214L,57215L,57216L,57217L,
94739 57218L,57219L,57220L,57221L,57222L,57223L,57224L,57225L,57226L,57227L,
94740 57228L,57229L,57230L,57231L,57232L,57233L,57234L,57235L,57236L,57237L,
94741 57238L,57239L,57240L,57241L,57242L,57243L,57244L,57245L,57246L,57247L,
94742 57248L,57249L,57250L,57251L,57252L,57253L,57254L,57255L,57256L,57257L,
94743 57258L,57259L,57260L,57261L,57262L,57263L,57264L,57265L,57266L,57267L,
94744 57268L,57269L,57270L,57271L,57272L,57273L,57274L,57275L,57276L,57277L,
94745 57278L,57279L,57280L,57281L,57282L,57283L,57284L,57285L,57286L,57287L,
94746 57288L,57289L,57290L,57291L,57292L,57293L,57294L,57295L,57296L,57297L,
94747 57298L,57299L,57300L,57301L,57302L,57303L,57304L,57305L,57306L,57307L,
94748 57308L,57309L,57310L,57311L,57312L,57313L,57314L,57315L,57316L,57317L,
94749 57318L,57319L,57320L,57321L,57322L,57323L,57324L,57325L,57326L,57327L,
94750 57328L,57329L,57330L,57331L,57332L,57333L,57334L,57335L,57336L,57337L,
94751 57338L,57339L,57340L,57341L,57342L,57343L,57344L,57345L,57346L,57347L,
94752 57348L,57349L,57350L,57351L,57352L,57353L,57354L,57355L,57356L,57357L,
94753 57358L,57359L,57360L,57361L,57362L,57363L,57364L,57365L,57366L,57367L,
94754 57368L,57369L,57370L,57371L,57372L,57373L,57374L,57375L,57376L,57377L,
94755 57378L,57379L,57380L,57381L,57382L,57383L,57384L,57385L,57386L,57387L,
94756 57388L,57389L,57390L,57391L,57392L,57393L,57394L,57395L,57396L,57397L,
94757 57398L,57399L,57400L,57401L,57402L,57403L,57404L,57405L,57406L,57407L,
94758 57408L,57409L,57410L,57411L,57412L,57413L,57414L,57415L,57416L,57417L,
94759 57418L,57419L,57420L,57421L,57422L,57423L,57424L,57425L,57426L,57427L,
94760 57428L,57429L,57430L,57431L,57432L,57433L,57434L,57435L,57436L,57437L,
94761 57438L,57439L,57440L,57441L,57442L,57443L,57444L,57445L,57446L,57447L,
94762 57448L,57449L,57450L,57451L,57452L,57453L,57454L,57455L,57456L,57457L,
94763 57458L,57459L,57460L,57461L,57462L,57463L,57464L,57465L,57466L,57467L,
94764 57468L,57469L,57470L,57471L,57472L,57473L,57474L,57475L,57476L,57477L,
94765 57478L,57479L,57480L,57481L,57482L,57483L,57484L,57485L,57486L,57487L,
94766 57488L,57489L,57490L,57491L,57492L,57493L,57494L,57495L,57496L,57497L,
94767 57498L,57499L,57500L,57501L,57502L,57503L,57504L,57505L,57506L,57507L,
94768 57508L,57509L,57510L,57511L,57512L,57513L,57514L,57515L,57516L,57517L,
94769 57518L,57519L,57520L,57521L,57522L,57523L,57524L,57525L,57526L,57527L,
94770 57528L,57529L,57530L,57531L,57532L,57533L,57534L,57535L,57536L,57537L,
94771 57538L,57539L,57540L,57541L,57542L,57543L,57544L,57545L,57546L,57547L,
94772 57548L,57549L,57550L,57551L,57552L,57553L,57554L,57555L,57556L,57557L,
94773 57558L,57559L,57560L,57561L,57562L,57563L,57564L,57565L,57566L,57567L,
94774 57568L,57569L,57570L,57571L,57572L,57573L,57574L,57575L,57576L,57577L,
94775 57578L,57579L,57580L,57581L,57582L,57583L,57584L,57585L,57586L,57587L,
94776 57588L,57589L,57590L,57591L,57592L,57593L,57594L,57595L,57596L,57597L,
94777 57598L,57599L,57600L,57601L,57602L,57603L,57604L,57605L,57606L,57607L,
94778 57608L,57609L,57610L,57611L,57612L,57613L,57614L,57615L,57616L,57617L,
94779 57618L,57619L,57620L,57621L,57622L,57623L,57624L,57625L,57626L,57627L,
94780 57628L,57629L,57630L,57631L,57632L,57633L,57634L,57635L,57636L,57637L,
94781 57638L,57639L,57640L,57641L,57642L,57643L,57644L,57645L,57646L,57647L,
94782 57648L,57649L,57650L,57651L,57652L,57653L,57654L,57655L,57656L,57657L,
94783 57658L,57659L,57660L,57661L,57662L,57663L,57664L,57665L,57666L,57667L,
94784 57668L,57669L,57670L,57671L,57672L,57673L,57674L,57675L,57676L,57677L,
94785 57678L,57679L,57680L,57681L,57682L,57683L,57684L,57685L,57686L,57687L,
94786 57688L,57689L,57690L,57691L,57692L,57693L,57694L,57695L,57696L,57697L,
94787 57698L,57699L,57700L,57701L,57702L,57703L,57704L,57705L,57706L,57707L,
94788 57708L,57709L,57710L,57711L,57712L,57713L,57714L,57715L,57716L,57717L,
94789 57718L,57719L,57720L,57721L,57722L,57723L,57724L,57725L,57726L,57727L,
94790 57728L,57729L,57730L,57731L,57732L,57733L,57734L,57735L,57736L,57737L,
94791 57738L,57739L,57740L,57741L,57742L,57743L,57744L,57745L,57746L,57747L,
94792 57748L,57749L,57750L,57751L,57752L,57753L,57754L,57755L,57756L,57757L,
94793 57758L,57759L,57760L,57761L,57762L,57763L,57764L,57765L,57766L,57767L,
94794 57768L,57769L,57770L,57771L,57772L,57773L,57774L,57775L,57776L,57777L,
94795 57778L,57779L,57780L,57781L,57782L,57783L,57784L,57785L,57786L,57787L,
94796 57788L,57789L,57790L,57791L,57792L,57793L,57794L,57795L,57796L,57797L,
94797 57798L,57799L,57800L,57801L,57802L,57803L,57804L,57805L,57806L,57807L,
94798 57808L,57809L,57810L,57811L,57812L,57813L,57814L,57815L,57816L,57817L,
94799 57818L,57819L,57820L,57821L,57822L,57823L,57824L,57825L,57826L,57827L,
94800 57828L,57829L,57830L,57831L,57832L,57833L,57834L,57835L,57836L,57837L,
94801 57838L,57839L,57840L,57841L,57842L,57843L,57844L,57845L,57846L,57847L,
94802 57848L,57849L,57850L,57851L,57852L,57853L,57854L,57855L,57856L,57857L,
94803 57858L,57859L,57860L,57861L,57862L,57863L,57864L,57865L,57866L,57867L,
94804 57868L,57869L,57870L,57871L,57872L,57873L,57874L,57875L,57876L,57877L,
94805 57878L,57879L,57880L,57881L,57882L,57883L,57884L,57885L,57886L,57887L,
94806 57888L,57889L,57890L,57891L,57892L,57893L,57894L,57895L,57896L,57897L,
94807 57898L,57899L,57900L,57901L,57902L,57903L,57904L,57905L,57906L,57907L,
94808 57908L,57909L,57910L,57911L,57912L,57913L,57914L,57915L,57916L,57917L,
94809 57918L,57919L,57920L,57921L,57922L,57923L,57924L,57925L,57926L,57927L,
94810 57928L,57929L,57930L,57931L,57932L,57933L,57934L,57935L,57936L,57937L,
94811 57938L,57939L,57940L,57941L,57942L,57943L,57944L,57945L,57946L,57947L,
94812 57948L,57949L,57950L,57951L,57952L,57953L,57954L,57955L,57956L,57957L,
94813 57958L,57959L,57960L,57961L,57962L,57963L,57964L,57965L,57966L,57967L,
94814 57968L,57969L,57970L,57971L,57972L,57973L,57974L,57975L,57976L,57977L,
94815 57978L,57979L,57980L,57981L,57982L,57983L,57984L,57985L,57986L,57987L,
94816 57988L,57989L,57990L,57991L,57992L,57993L,57994L,57995L,57996L,57997L,
94817 57998L,57999L,58000L,58001L,58002L,58003L,58004L,58005L,58006L,58007L,
94818 58008L,58009L,58010L,58011L,58012L,58013L,58014L,58015L,58016L,58017L,
94819 58018L,58019L,58020L,58021L,58022L,58023L,58024L,58025L,58026L,58027L,
94820 58028L,58029L,58030L,58031L,58032L,58033L,58034L,58035L,58036L,58037L,
94821 58038L,58039L,58040L,58041L,58042L,58043L,58044L,58045L,58046L,58047L,
94822 58048L,58049L,58050L,58051L,58052L,58053L,58054L,58055L,58056L,58057L,
94823 58058L,58059L,58060L,58061L,58062L,58063L,58064L,58065L,58066L,58067L,
94824 58068L,58069L,58070L,58071L,58072L,58073L,58074L,58075L,58076L,58077L,
94825 58078L,58079L,58080L,58081L,58082L,58083L,58084L,58085L,58086L,58087L,
94826 58088L,58089L,58090L,58091L,58092L,58093L,58094L,58095L,58096L,58097L,
94827 58098L,58099L,58100L,58101L,58102L,58103L,58104L,58105L,58106L,58107L,
94828 58108L,58109L,58110L,58111L,58112L,58113L,58114L,58115L,58116L,58117L,
94829 58118L,58119L,58120L,58121L,58122L,58123L,58124L,58125L,58126L,58127L,
94830 58128L,58129L,58130L,58131L,58132L,58133L,58134L,58135L,58136L,58137L,
94831 58138L,58139L,58140L,58141L,58142L,58143L,58144L,58145L,58146L,58147L,
94832 58148L,58149L,58150L,58151L,58152L,58153L,58154L,58155L,58156L,58157L,
94833 58158L,58159L,58160L,58161L,58162L,58163L,58164L,58165L,58166L,58167L,
94834 58168L,58169L,58170L,58171L,58172L,58173L,58174L,58175L,58176L,58177L,
94835 58178L,58179L,58180L,58181L,58182L,58183L,58184L,58185L,58186L,58187L,
94836 58188L,58189L,58190L,58191L,58192L,58193L,58194L,58195L,58196L,58197L,
94837 58198L,58199L,58200L,58201L,58202L,58203L,58204L,58205L,58206L,58207L,
94838 58208L,58209L,58210L,58211L,58212L,58213L,58214L,58215L,58216L,58217L,
94839 58218L,58219L,58220L,58221L,58222L,58223L,58224L,58225L,58226L,58227L,
94840 58228L,58229L,58230L,58231L,58232L,58233L,58234L,58235L,58236L,58237L,
94841 58238L,58239L,58240L,58241L,58242L,58243L,58244L,58245L,58246L,58247L,
94842 58248L,58249L,58250L,58251L,58252L,58253L,58254L,58255L,58256L,58257L,
94843 58258L,58259L,58260L,58261L,58262L,58263L,58264L,58265L,58266L,58267L,
94844 58268L,58269L,58270L,58271L,58272L,58273L,58274L,58275L,58276L,58277L,
94845 58278L,58279L,58280L,58281L,58282L,58283L,58284L,58285L,58286L,58287L,
94846 58288L,58289L,58290L,58291L,58292L,58293L,58294L,58295L,58296L,58297L,
94847 58298L,58299L,58300L,58301L,58302L,58303L,58304L,58305L,58306L,58307L,
94848 58308L,58309L,58310L,58311L,58312L,58313L,58314L,58315L,58316L,58317L,
94849 58318L,58319L,58320L,58321L,58322L,58323L,58324L,58325L,58326L,58327L,
94850 58328L,58329L,58330L,58331L,58332L,58333L,58334L,58335L,58336L,58337L,
94851 58338L,58339L,58340L,58341L,58342L,58343L,58344L,58345L,58346L,58347L,
94852 58348L,58349L,58350L,58351L,58352L,58353L,58354L,58355L,58356L,58357L,
94853 58358L,58359L,58360L,58361L,58362L,58363L,58364L,58365L,58366L,58367L,
94854 58368L,58369L,58370L,58371L,58372L,58373L,58374L,58375L,58376L,58377L,
94855 58378L,58379L,58380L,58381L,58382L,58383L,58384L,58385L,58386L,58387L,
94856 58388L,58389L,58390L,58391L,58392L,58393L,58394L,58395L,58396L,58397L,
94857 58398L,58399L,58400L,58401L,58402L,58403L,58404L,58405L,58406L,58407L,
94858 58408L,58409L,58410L,58411L,58412L,58413L,58414L,58415L,58416L,58417L,
94859 58418L,58419L,58420L,58421L,58422L,58423L,58424L,58425L,58426L,58427L,
94860 58428L,58429L,58430L,58431L,58432L,58433L,58434L,58435L,58436L,58437L,
94861 58438L,58439L,58440L,58441L,58442L,58443L,58444L,58445L,58446L,58447L,
94862 58448L,58449L,58450L,58451L,58452L,58453L,58454L,58455L,58456L,58457L,
94863 58458L,58459L,58460L,58461L,58462L,58463L,58464L,58465L,58466L,58467L,
94864 58468L,58469L,58470L,58471L,58472L,58473L,58474L,58475L,58476L,58477L,
94865 58478L,58479L,58480L,58481L,58482L,58483L,58484L,58485L,58486L,58487L,
94866 58488L,58489L,58490L,58491L,58492L,58493L,58494L,58495L,58496L,58497L,
94867 58498L,58499L,58500L,58501L,58502L,58503L,58504L,58505L,58506L,58507L,
94868 58508L,58509L,58510L,58511L,58512L,58513L,58514L,58515L,58516L,58517L,
94869 58518L,58519L,58520L,58521L,58522L,58523L,58524L,58525L,58526L,58527L,
94870 58528L,58529L,58530L,58531L,58532L,58533L,58534L,58535L,58536L,58537L,
94871 58538L,58539L,58540L,58541L,58542L,58543L,58544L,58545L,58546L,58547L,
94872 58548L,58549L,58550L,58551L,58552L,58553L,58554L,58555L,58556L,58557L,
94873 58558L,58559L,58560L,58561L,58562L,58563L,58564L,58565L,58566L,58567L,
94874 58568L,58569L,58570L,58571L,58572L,58573L,58574L,58575L,58576L,58577L,
94875 58578L,58579L,58580L,58581L,58582L,58583L,58584L,58585L,58586L,58587L,
94876 58588L,58589L,58590L,58591L,58592L,58593L,58594L,58595L,58596L,58597L,
94877 58598L,58599L,58600L,58601L,58602L,58603L,58604L,58605L,58606L,58607L,
94878 58608L,58609L,58610L,58611L,58612L,58613L,58614L,58615L,58616L,58617L,
94879 58618L,58619L,58620L,58621L,58622L,58623L,58624L,58625L,58626L,58627L,
94880 58628L,58629L,58630L,58631L,58632L,58633L,58634L,58635L,58636L,58637L,
94881 58638L,58639L,58640L,58641L,58642L,58643L,58644L,58645L,58646L,58647L,
94882 58648L,58649L,58650L,58651L,58652L,58653L,58654L,58655L,58656L,58657L,
94883 58658L,58659L,58660L,58661L,58662L,58663L,58664L,58665L,58666L,58667L,
94884 58668L,58669L,58670L,58671L,58672L,58673L,58674L,58675L,58676L,58677L,
94885 58678L,58679L,58680L,58681L,58682L,58683L,58684L,58685L,58686L,58687L,
94886 58688L,58689L,58690L,58691L,58692L,58693L,58694L,58695L,58696L,58697L,
94887 58698L,58699L,58700L,58701L,58702L,58703L,58704L,58705L,58706L,58707L,
94888 58708L,58709L,58710L,58711L,58712L,58713L,58714L,58715L,58716L,58717L,
94889 58718L,58719L,58720L,58721L,58722L,58723L,58724L,58725L,58726L,58727L,
94890 58728L,58729L,58730L,58731L,58732L,58733L,58734L,58735L,58736L,58737L,
94891 58738L,58739L,58740L,58741L,58742L,58743L,58744L,58745L,58746L,58747L,
94892 58748L,58749L,58750L,58751L,58752L,58753L,58754L,58755L,58756L,58757L,
94893 58758L,58759L,58760L,58761L,58762L,58763L,58764L,58765L,58766L,58767L,
94894 58768L,58769L,58770L,58771L,58772L,58773L,58774L,58775L,58776L,58777L,
94895 58778L,58779L,58780L,58781L,58782L,58783L,58784L,58785L,58786L,58787L,
94896 58788L,58789L,58790L,58791L,58792L,58793L,58794L,58795L,58796L,58797L,
94897 58798L,58799L,58800L,58801L,58802L,58803L,58804L,58805L,58806L,58807L,
94898 58808L,58809L,58810L,58811L,58812L,58813L,58814L,58815L,58816L,58817L,
94899 58818L,58819L,58820L,58821L,58822L,58823L,58824L,58825L,58826L,58827L,
94900 58828L,58829L,58830L,58831L,58832L,58833L,58834L,58835L,58836L,58837L,
94901 58838L,58839L,58840L,58841L,58842L,58843L,58844L,58845L,58846L,58847L,
94902 58848L,58849L,58850L,58851L,58852L,58853L,58854L,58855L,58856L,58857L,
94903 58858L,58859L,58860L,58861L,58862L,58863L,58864L,58865L,58866L,58867L,
94904 58868L,58869L,58870L,58871L,58872L,58873L,58874L,58875L,58876L,58877L,
94905 58878L,58879L,58880L,58881L,58882L,58883L,58884L,58885L,58886L,58887L,
94906 58888L,58889L,58890L,58891L,58892L,58893L,58894L,58895L,58896L,58897L,
94907 58898L,58899L,58900L,58901L,58902L,58903L,58904L,58905L,58906L,58907L,
94908 58908L,58909L,58910L,58911L,58912L,58913L,58914L,58915L,58916L,58917L,
94909 58918L,58919L,58920L,58921L,58922L,58923L,58924L,58925L,58926L,58927L,
94910 58928L,58929L,58930L,58931L,58932L,58933L,58934L,58935L,58936L,58937L,
94911 58938L,58939L,58940L,58941L,58942L,58943L,58944L,58945L,58946L,58947L,
94912 58948L,58949L,58950L,58951L,58952L,58953L,58954L,58955L,58956L,58957L,
94913 58958L,58959L,58960L,58961L,58962L,58963L,58964L,58965L,58966L,58967L,
94914 58968L,58969L,58970L,58971L,58972L,58973L,58974L,58975L,58976L,58977L,
94915 58978L,58979L,58980L,58981L,58982L,58983L,58984L,58985L,58986L,58987L,
94916 58988L,58989L,58990L,58991L,58992L,58993L,58994L,58995L,58996L,58997L,
94917 58998L,58999L,59000L,59001L,59002L,59003L,59004L,59005L,59006L,59007L,
94918 59008L,59009L,59010L,59011L,59012L,59013L,59014L,59015L,59016L,59017L,
94919 59018L,59019L,59020L,59021L,59022L,59023L,59024L,59025L,59026L,59027L,
94920 59028L,59029L,59030L,59031L,59032L,59033L,59034L,59035L,59036L,59037L,
94921 59038L,59039L,59040L,59041L,59042L,59043L,59044L,59045L,59046L,59047L,
94922 59048L,59049L,59050L,59051L,59052L,59053L,59054L,59055L,59056L,59057L,
94923 59058L,59059L,59060L,59061L,59062L,59063L,59064L,59065L,59066L,59067L,
94924 59068L,59069L,59070L,59071L,59072L,59073L,59074L,59075L,59076L,59077L,
94925 59078L,59079L,59080L,59081L,59082L,59083L,59084L,59085L,59086L,59087L,
94926 59088L,59089L,59090L,59091L,59092L,59093L,59094L,59095L,59096L,59097L,
94927 59098L,59099L,59100L,59101L,59102L,59103L,59104L,59105L,59106L,59107L,
94928 59108L,59109L,59110L,59111L,59112L,59113L,59114L,59115L,59116L,59117L,
94929 59118L,59119L,59120L,59121L,59122L,59123L,59124L,59125L,59126L,59127L,
94930 59128L,59129L,59130L,59131L,59132L,59133L,59134L,59135L,59136L,59137L,
94931 59138L,59139L,59140L,59141L,59142L,59143L,59144L,59145L,59146L,59147L,
94932 59148L,59149L,59150L,59151L,59152L,59153L,59154L,59155L,59156L,59157L,
94933 59158L,59159L,59160L,59161L,59162L,59163L,59164L,59165L,59166L,59167L,
94934 59168L,59169L,59170L,59171L,59172L,59173L,59174L,59175L,59176L,59177L,
94935 59178L,59179L,59180L,59181L,59182L,59183L,59184L,59185L,59186L,59187L,
94936 59188L,59189L,59190L,59191L,59192L,59193L,59194L,59195L,59196L,59197L,
94937 59198L,59199L,59200L,59201L,59202L,59203L,59204L,59205L,59206L,59207L,
94938 59208L,59209L,59210L,59211L,59212L,59213L,59214L,59215L,59216L,59217L,
94939 59218L,59219L,59220L,59221L,59222L,59223L,59224L,59225L,59226L,59227L,
94940 59228L,59229L,59230L,59231L,59232L,59233L,59234L,59235L,59236L,59237L,
94941 59238L,59239L,59240L,59241L,59242L,59243L,59244L,59245L,59246L,59247L,
94942 59248L,59249L,59250L,59251L,59252L,59253L,59254L,59255L,59256L,59257L,
94943 59258L,59259L,59260L,59261L,59262L,59263L,59264L,59265L,59266L,59267L,
94944 59268L,59269L,59270L,59271L,59272L,59273L,59274L,59275L,59276L,59277L,
94945 59278L,59279L,59280L,59281L,59282L,59283L,59284L,59285L,59286L,59287L,
94946 59288L,59289L,59290L,59291L,59292L,59293L,59294L,59295L,59296L,59297L,
94947 59298L,59299L,59300L,59301L,59302L,59303L,59304L,59305L,59306L,59307L,
94948 59308L,59309L,59310L,59311L,59312L,59313L,59314L,59315L,59316L,59317L,
94949 59318L,59319L,59320L,59321L,59322L,59323L,59324L,59325L,59326L,59327L,
94950 59328L,59329L,59330L,59331L,59332L,59333L,59334L,59335L,59336L,59337L,
94951 59338L,59339L,59340L,59341L,59342L,59343L,59344L,59345L,59346L,59347L,
94952 59348L,59349L,59350L,59351L,59352L,59353L,59354L,59355L,59356L,59357L,
94953 59358L,59359L,59360L,59361L,59362L,59363L,59364L,59365L,59366L,59367L,
94954 59368L,59369L,59370L,59371L,59372L,59373L,59374L,59375L,59376L,59377L,
94955 59378L,59379L,59380L,59381L,59382L,59383L,59384L,59385L,59386L,59387L,
94956 59388L,59389L,59390L,59391L,59392L,59393L,59394L,59395L,59396L,59397L,
94957 59398L,59399L,59400L,59401L,59402L,59403L,59404L,59405L,59406L,59407L,
94958 59408L,59409L,59410L,59411L,59412L,59413L,59414L,59415L,59416L,59417L,
94959 59418L,59419L,59420L,59421L,59422L,59423L,59424L,59425L,59426L,59427L,
94960 59428L,59429L,59430L,59431L,59432L,59433L,59434L,59435L,59436L,59437L,
94961 59438L,59439L,59440L,59441L,59442L,59443L,59444L,59445L,59446L,59447L,
94962 59448L,59449L,59450L,59451L,59452L,59453L,59454L,59455L,59456L,59457L,
94963 59458L,59459L,59460L,59461L,59462L,59463L,59464L,59465L,59466L,59467L,
94964 59468L,59469L,59470L,59471L,59472L,59473L,59474L,59475L,59476L,59477L,
94965 59478L,59479L,59480L,59481L,59482L,59483L,59484L,59485L,59486L,59487L,
94966 59488L,59489L,59490L,59491L,59492L,59493L,59494L,59495L,59496L,59497L,
94967 59498L,59499L,59500L,59501L,59502L,59503L,59504L,59505L,59506L,59507L,
94968 59508L,59509L,59510L,59511L,59512L,59513L,59514L,59515L,59516L,59517L,
94969 59518L,59519L,59520L,59521L,59522L,59523L,59524L,59525L,59526L,59527L,
94970 59528L,59529L,59530L,59531L,59532L,59533L,59534L,59535L,59536L,59537L,
94971 59538L,59539L,59540L,59541L,59542L,59543L,59544L,59545L,59546L,59547L,
94972 59548L,59549L,59550L,59551L,59552L,59553L,59554L,59555L,59556L,59557L,
94973 59558L,59559L,59560L,59561L,59562L,59563L,59564L,59565L,59566L,59567L,
94974 59568L,59569L,59570L,59571L,59572L,59573L,59574L,59575L,59576L,59577L,
94975 59578L,59579L,59580L,59581L,59582L,59583L,59584L,59585L,59586L,59587L,
94976 59588L,59589L,59590L,59591L,59592L,59593L,59594L,59595L,59596L,59597L,
94977 59598L,59599L,59600L,59601L,59602L,59603L,59604L,59605L,59606L,59607L,
94978 59608L,59609L,59610L,59611L,59612L,59613L,59614L,59615L,59616L,59617L,
94979 59618L,59619L,59620L,59621L,59622L,59623L,59624L,59625L,59626L,59627L,
94980 59628L,59629L,59630L,59631L,59632L,59633L,59634L,59635L,59636L,59637L,
94981 59638L,59639L,59640L,59641L,59642L,59643L,59644L,59645L,59646L,59647L,
94982 59648L,59649L,59650L,59651L,59652L,59653L,59654L,59655L,59656L,59657L,
94983 59658L,59659L,59660L,59661L,59662L,59663L,59664L,59665L,59666L,59667L,
94984 59668L,59669L,59670L,59671L,59672L,59673L,59674L,59675L,59676L,59677L,
94985 59678L,59679L,59680L,59681L,59682L,59683L,59684L,59685L,59686L,59687L,
94986 59688L,59689L,59690L,59691L,59692L,59693L,59694L,59695L,59696L,59697L,
94987 59698L,59699L,59700L,59701L,59702L,59703L,59704L,59705L,59706L,59707L,
94988 59708L,59709L,59710L,59711L,59712L,59713L,59714L,59715L,59716L,59717L,
94989 59718L,59719L,59720L,59721L,59722L,59723L,59724L,59725L,59726L,59727L,
94990 59728L,59729L,59730L,59731L,59732L,59733L,59734L,59735L,59736L,59737L,
94991 59738L,59739L,59740L,59741L,59742L,59743L,59744L,59745L,59746L,59747L,
94992 59748L,59749L,59750L,59751L,59752L,59753L,59754L,59755L,59756L,59757L,
94993 59758L,59759L,59760L,59761L,59762L,59763L,59764L,59765L,59766L,59767L,
94994 59768L,59769L,59770L,59771L,59772L,59773L,59774L,59775L,59776L,59777L,
94995 59778L,59779L,59780L,59781L,59782L,59783L,59784L,59785L,59786L,59787L,
94996 59788L,59789L,59790L,59791L,59792L,59793L,59794L,59795L,59796L,59797L,
94997 59798L,59799L,59800L,59801L,59802L,59803L,59804L,59805L,59806L,59807L,
94998 59808L,59809L,59810L,59811L,59812L,59813L,59814L,59815L,59816L,59817L,
94999 59818L,59819L,59820L,59821L,59822L,59823L,59824L,59825L,59826L,59827L,
95000 59828L,59829L,59830L,59831L,59832L,59833L,59834L,59835L,59836L,59837L,
95001 59838L,59839L,59840L,59841L,59842L,59843L,59844L,59845L,59846L,59847L,
95002 59848L,59849L,59850L,59851L,59852L,59853L,59854L,59855L,59856L,59857L,
95003 59858L,59859L,59860L,59861L,59862L,59863L,59864L,59865L,59866L,59867L,
95004 59868L,59869L,59870L,59871L,59872L,59873L,59874L,59875L,59876L,59877L,
95005 59878L,59879L,59880L,59881L,59882L,59883L,59884L,59885L,59886L,59887L,
95006 59888L,59889L,59890L,59891L,59892L,59893L,59894L,59895L,59896L,59897L,
95007 59898L,59899L,59900L,59901L,59902L,59903L,59904L,59905L,59906L,59907L,
95008 59908L,59909L,59910L,59911L,59912L,59913L,59914L,59915L,59916L,59917L,
95009 59918L,59919L,59920L,59921L,59922L,59923L,59924L,59925L,59926L,59927L,
95010 59928L,59929L,59930L,59931L,59932L,59933L,59934L,59935L,59936L,59937L,
95011 59938L,59939L,59940L,59941L,59942L,59943L,59944L,59945L,59946L,59947L,
95012 59948L,59949L,59950L,59951L,59952L,59953L,59954L,59955L,59956L,59957L,
95013 59958L,59959L,59960L,59961L,59962L,59963L,59964L,59965L,59966L,59967L,
95014 59968L,59969L,59970L,59971L,59972L,59973L,59974L,59975L,59976L,59977L,
95015 59978L,59979L,59980L,59981L,59982L,59983L,59984L,59985L,59986L,59987L,
95016 59988L,59989L,59990L,59991L,59992L,59993L,59994L,59995L,59996L,59997L,
95017 59998L,59999L,60000L,60001L,60002L,60003L,60004L,60005L,60006L,60007L,
95018 60008L,60009L,60010L,60011L,60012L,60013L,60014L,60015L,60016L,60017L,
95019 60018L,60019L,60020L,60021L,60022L,60023L,60024L,60025L,60026L,60027L,
95020 60028L,60029L,60030L,60031L,60032L,60033L,60034L,60035L,60036L,60037L,
95021 60038L,60039L,60040L,60041L,60042L,60043L,60044L,60045L,60046L,60047L,
95022 60048L,60049L,60050L,60051L,60052L,60053L,60054L,60055L,60056L,60057L,
95023 60058L,60059L,60060L,60061L,60062L,60063L,60064L,60065L,60066L,60067L,
95024 60068L,60069L,60070L,60071L,60072L,60073L,60074L,60075L,60076L,60077L,
95025 60078L,60079L,60080L,60081L,60082L,60083L,60084L,60085L,60086L,60087L,
95026 60088L,60089L,60090L,60091L,60092L,60093L,60094L,60095L,60096L,60097L,
95027 60098L,60099L,60100L,60101L,60102L,60103L,60104L,60105L,60106L,60107L,
95028 60108L,60109L,60110L,60111L,60112L,60113L,60114L,60115L,60116L,60117L,
95029 60118L,60119L,60120L,60121L,60122L,60123L,60124L,60125L,60126L,60127L,
95030 60128L,60129L,60130L,60131L,60132L,60133L,60134L,60135L,60136L,60137L,
95031 60138L,60139L,60140L,60141L,60142L,60143L,60144L,60145L,60146L,60147L,
95032 60148L,60149L,60150L,60151L,60152L,60153L,60154L,60155L,60156L,60157L,
95033 60158L,60159L,60160L,60161L,60162L,60163L,60164L,60165L,60166L,60167L,
95034 60168L,60169L,60170L,60171L,60172L,60173L,60174L,60175L,60176L,60177L,
95035 60178L,60179L,60180L,60181L,60182L,60183L,60184L,60185L,60186L,60187L,
95036 60188L,60189L,60190L,60191L,60192L,60193L,60194L,60195L,60196L,60197L,
95037 60198L,60199L,60200L,60201L,60202L,60203L,60204L,60205L,60206L,60207L,
95038 60208L,60209L,60210L,60211L,60212L,60213L,60214L,60215L,60216L,60217L,
95039 60218L,60219L,60220L,60221L,60222L,60223L,60224L,60225L,60226L,60227L,
95040 60228L,60229L,60230L,60231L,60232L,60233L,60234L,60235L,60236L,60237L,
95041 60238L,60239L,60240L,60241L,60242L,60243L,60244L,60245L,60246L,60247L,
95042 60248L,60249L,60250L,60251L,60252L,60253L,60254L,60255L,60256L,60257L,
95043 60258L,60259L,60260L,60261L,60262L,60263L,60264L,60265L,60266L,60267L,
95044 60268L,60269L,60270L,60271L,60272L,60273L,60274L,60275L,60276L,60277L,
95045 60278L,60279L,60280L,60281L,60282L,60283L,60284L,60285L,60286L,60287L,
95046 60288L,60289L,60290L,60291L,60292L,60293L,60294L,60295L,60296L,60297L,
95047 60298L,60299L,60300L,60301L,60302L,60303L,60304L,60305L,60306L,60307L,
95048 60308L,60309L,60310L,60311L,60312L,60313L,60314L,60315L,60316L,60317L,
95049 60318L,60319L,60320L,60321L,60322L,60323L,60324L,60325L,60326L,60327L,
95050 60328L,60329L,60330L,60331L,60332L,60333L,60334L,60335L,60336L,60337L,
95051 60338L,60339L,60340L,60341L,60342L,60343L,60344L,60345L,60346L,60347L,
95052 60348L,60349L,60350L,60351L,60352L,60353L,60354L,60355L,60356L,60357L,
95053 60358L,60359L,60360L,60361L,60362L,60363L,60364L,60365L,60366L,60367L,
95054 60368L,60369L,60370L,60371L,60372L,60373L,60374L,60375L,60376L,60377L,
95055 60378L,60379L,60380L,60381L,60382L,60383L,60384L,60385L,60386L,60387L,
95056 60388L,60389L,60390L,60391L,60392L,60393L,60394L,60395L,60396L,60397L,
95057 60398L,60399L,60400L,60401L,60402L,60403L,60404L,60405L,60406L,60407L,
95058 60408L,60409L,60410L,60411L,60412L,60413L,60414L,60415L,60416L,60417L,
95059 60418L,60419L,60420L,60421L,60422L,60423L,60424L,60425L,60426L,60427L,
95060 60428L,60429L,60430L,60431L,60432L,60433L,60434L,60435L,60436L,60437L,
95061 60438L,60439L,60440L,60441L,60442L,60443L,60444L,60445L,60446L,60447L,
95062 60448L,60449L,60450L,60451L,60452L,60453L,60454L,60455L,60456L,60457L,
95063 60458L,60459L,60460L,60461L,60462L,60463L,60464L,60465L,60466L,60467L,
95064 60468L,60469L,60470L,60471L,60472L,60473L,60474L,60475L,60476L,60477L,
95065 60478L,60479L,60480L,60481L,60482L,60483L,60484L,60485L,60486L,60487L,
95066 60488L,60489L,60490L,60491L,60492L,60493L,60494L,60495L,60496L,60497L,
95067 60498L,60499L,60500L,60501L,60502L,60503L,60504L,60505L,60506L,60507L,
95068 60508L,60509L,60510L,60511L,60512L,60513L,60514L,60515L,60516L,60517L,
95069 60518L,60519L,60520L,60521L,60522L,60523L,60524L,60525L,60526L,60527L,
95070 60528L,60529L,60530L,60531L,60532L,60533L,60534L,60535L,60536L,60537L,
95071 60538L,60539L,60540L,60541L,60542L,60543L,60544L,60545L,60546L,60547L,
95072 60548L,60549L,60550L,60551L,60552L,60553L,60554L,60555L,60556L,60557L,
95073 60558L,60559L,60560L,60561L,60562L,60563L,60564L,60565L,60566L,60567L,
95074 60568L,60569L,60570L,60571L,60572L,60573L,60574L,60575L,60576L,60577L,
95075 60578L,60579L,60580L,60581L,60582L,60583L,60584L,60585L,60586L,60587L,
95076 60588L,60589L,60590L,60591L,60592L,60593L,60594L,60595L,60596L,60597L,
95077 60598L,60599L,60600L,60601L,60602L,60603L,60604L,60605L,60606L,60607L,
95078 60608L,60609L,60610L,60611L,60612L,60613L,60614L,60615L,60616L,60617L,
95079 60618L,60619L,60620L,60621L,60622L,60623L,60624L,60625L,60626L,60627L,
95080 60628L,60629L,60630L,60631L,60632L,60633L,60634L,60635L,60636L,60637L,
95081 60638L,60639L,60640L,60641L,60642L,60643L,60644L,60645L,60646L,60647L,
95082 60648L,60649L,60650L,60651L,60652L,60653L,60654L,60655L,60656L,60657L,
95083 60658L,60659L,60660L,60661L,60662L,60663L,60664L,60665L,60666L,60667L,
95084 60668L,60669L,60670L,60671L,60672L,60673L,60674L,60675L,60676L,60677L,
95085 60678L,60679L,60680L,60681L,60682L,60683L,60684L,60685L,60686L,60687L,
95086 60688L,60689L,60690L,60691L,60692L,60693L,60694L,60695L,60696L,60697L,
95087 60698L,60699L,60700L,60701L,60702L,60703L,60704L,60705L,60706L,60707L,
95088 60708L,60709L,60710L,60711L,60712L,60713L,60714L,60715L,60716L,60717L,
95089 60718L,60719L,60720L,60721L,60722L,60723L,60724L,60725L,60726L,60727L,
95090 60728L,60729L,60730L,60731L,60732L,60733L,60734L,60735L,60736L,60737L,
95091 60738L,60739L,60740L,60741L,60742L,60743L,60744L,60745L,60746L,60747L,
95092 60748L,60749L,60750L,60751L,60752L,60753L,60754L,60755L,60756L,60757L,
95093 60758L,60759L,60760L,60761L,60762L,60763L,60764L,60765L,60766L,60767L,
95094 60768L,60769L,60770L,60771L,60772L,60773L,60774L,60775L,60776L,60777L,
95095 60778L,60779L,60780L,60781L,60782L,60783L,60784L,60785L,60786L,60787L,
95096 60788L,60789L,60790L,60791L,60792L,60793L,60794L,60795L,60796L,60797L,
95097 60798L,60799L,60800L,60801L,60802L,60803L,60804L,60805L,60806L,60807L,
95098 60808L,60809L,60810L,60811L,60812L,60813L,60814L,60815L,60816L,60817L,
95099 60818L,60819L,60820L,60821L,60822L,60823L,60824L,60825L,60826L,60827L,
95100 60828L,60829L,60830L,60831L,60832L,60833L,60834L,60835L,60836L,60837L,
95101 60838L,60839L,60840L,60841L,60842L,60843L,60844L,60845L,60846L,60847L,
95102 60848L,60849L,60850L,60851L,60852L,60853L,60854L,60855L,60856L,60857L,
95103 60858L,60859L,60860L,60861L,60862L,60863L,60864L,60865L,60866L,60867L,
95104 60868L,60869L,60870L,60871L,60872L,60873L,60874L,60875L,60876L,60877L,
95105 60878L,60879L,60880L,60881L,60882L,60883L,60884L,60885L,60886L,60887L,
95106 60888L,60889L,60890L,60891L,60892L,60893L,60894L,60895L,60896L,60897L,
95107 60898L,60899L,60900L,60901L,60902L,60903L,60904L,60905L,60906L,60907L,
95108 60908L,60909L,60910L,60911L,60912L,60913L,60914L,60915L,60916L,60917L,
95109 60918L,60919L,60920L,60921L,60922L,60923L,60924L,60925L,60926L,60927L,
95110 60928L,60929L,60930L,60931L,60932L,60933L,60934L,60935L,60936L,60937L,
95111 60938L,60939L,60940L,60941L,60942L,60943L,60944L,60945L,60946L,60947L,
95112 60948L,60949L,60950L,60951L,60952L,60953L,60954L,60955L,60956L,60957L,
95113 60958L,60959L,60960L,60961L,60962L,60963L,60964L,60965L,60966L,60967L,
95114 60968L,60969L,60970L,60971L,60972L,60973L,60974L,60975L,60976L,60977L,
95115 60978L,60979L,60980L,60981L,60982L,60983L,60984L,60985L,60986L,60987L,
95116 60988L,60989L,60990L,60991L,60992L,60993L,60994L,60995L,60996L,60997L,
95117 60998L,60999L,61000L,61001L,61002L,61003L,61004L,61005L,61006L,61007L,
95118 61008L,61009L,61010L,61011L,61012L,61013L,61014L,61015L,61016L,61017L,
95119 61018L,61019L,61020L,61021L,61022L,61023L,61024L,61025L,61026L,61027L,
95120 61028L,61029L,61030L,61031L,61032L,61033L,61034L,61035L,61036L,61037L,
95121 61038L,61039L,61040L,61041L,61042L,61043L,61044L,61045L,61046L,61047L,
95122 61048L,61049L,61050L,61051L,61052L,61053L,61054L,61055L,61056L,61057L,
95123 61058L,61059L,61060L,61061L,61062L,61063L,61064L,61065L,61066L,61067L,
95124 61068L,61069L,61070L,61071L,61072L,61073L,61074L,61075L,61076L,61077L,
95125 61078L,61079L,61080L,61081L,61082L,61083L,61084L,61085L,61086L,61087L,
95126 61088L,61089L,61090L,61091L,61092L,61093L,61094L,61095L,61096L,61097L,
95127 61098L,61099L,61100L,61101L,61102L,61103L,61104L,61105L,61106L,61107L,
95128 61108L,61109L,61110L,61111L,61112L,61113L,61114L,61115L,61116L,61117L,
95129 61118L,61119L,61120L,61121L,61122L,61123L,61124L,61125L,61126L,61127L,
95130 61128L,61129L,61130L,61131L,61132L,61133L,61134L,61135L,61136L,61137L,
95131 61138L,61139L,61140L,61141L,61142L,61143L,61144L,61145L,61146L,61147L,
95132 61148L,61149L,61150L,61151L,61152L,61153L,61154L,61155L,61156L,61157L,
95133 61158L,61159L,61160L,61161L,61162L,61163L,61164L,61165L,61166L,61167L,
95134 61168L,61169L,61170L,61171L,61172L,61173L,61174L,61175L,61176L,61177L,
95135 61178L,61179L,61180L,61181L,61182L,61183L,61184L,61185L,61186L,61187L,
95136 61188L,61189L,61190L,61191L,61192L,61193L,61194L,61195L,61196L,61197L,
95137 61198L,61199L,61200L,61201L,61202L,61203L,61204L,61205L,61206L,61207L,
95138 61208L,61209L,61210L,61211L,61212L,61213L,61214L,61215L,61216L,61217L,
95139 61218L,61219L,61220L,61221L,61222L,61223L,61224L,61225L,61226L,61227L,
95140 61228L,61229L,61230L,61231L,61232L,61233L,61234L,61235L,61236L,61237L,
95141 61238L,61239L,61240L,61241L,61242L,61243L,61244L,61245L,61246L,61247L,
95142 61248L,61249L,61250L,61251L,61252L,61253L,61254L,61255L,61256L,61257L,
95143 61258L,61259L,61260L,61261L,61262L,61263L,61264L,61265L,61266L,61267L,
95144 61268L,61269L,61270L,61271L,61272L,61273L,61274L,61275L,61276L,61277L,
95145 61278L,61279L,61280L,61281L,61282L,61283L,61284L,61285L,61286L,61287L,
95146 61288L,61289L,61290L,61291L,61292L,61293L,61294L,61295L,61296L,61297L,
95147 61298L,61299L,61300L,61301L,61302L,61303L,61304L,61305L,61306L,61307L,
95148 61308L,61309L,61310L,61311L,61312L,61313L,61314L,61315L,61316L,61317L,
95149 61318L,61319L,61320L,61321L,61322L,61323L,61324L,61325L,61326L,61327L,
95150 61328L,61329L,61330L,61331L,61332L,61333L,61334L,61335L,61336L,61337L,
95151 61338L,61339L,61340L,61341L,61342L,61343L,61344L,61345L,61346L,61347L,
95152 61348L,61349L,61350L,61351L,61352L,61353L,61354L,61355L,61356L,61357L,
95153 61358L,61359L,61360L,61361L,61362L,61363L,61364L,61365L,61366L,61367L,
95154 61368L,61369L,61370L,61371L,61372L,61373L,61374L,61375L,61376L,61377L,
95155 61378L,61379L,61380L,61381L,61382L,61383L,61384L,61385L,61386L,61387L,
95156 61388L,61389L,61390L,61391L,61392L,61393L,61394L,61395L,61396L,61397L,
95157 61398L,61399L,61400L,61401L,61402L,61403L,61404L,61405L,61406L,61407L,
95158 61408L,61409L,61410L,61411L,61412L,61413L,61414L,61415L,61416L,61417L,
95159 61418L,61419L,61420L,61421L,61422L,61423L,61424L,61425L,61426L,61427L,
95160 61428L,61429L,61430L,61431L,61432L,61433L,61434L,61435L,61436L,61437L,
95161 61438L,61439L,61440L,61441L,61442L,61443L,61444L,61445L,61446L,61447L,
95162 61448L,61449L,61450L,61451L,61452L,61453L,61454L,61455L,61456L,61457L,
95163 61458L,61459L,61460L,61461L,61462L,61463L,61464L,61465L,61466L,61467L,
95164 61468L,61469L,61470L,61471L,61472L,61473L,61474L,61475L,61476L,61477L,
95165 61478L,61479L,61480L,61481L,61482L,61483L,61484L,61485L,61486L,61487L,
95166 61488L,61489L,61490L,61491L,61492L,61493L,61494L,61495L,61496L,61497L,
95167 61498L,61499L,61500L,61501L,61502L,61503L,61504L,61505L,61506L,61507L,
95168 61508L,61509L,61510L,61511L,61512L,61513L,61514L,61515L,61516L,61517L,
95169 61518L,61519L,61520L,61521L,61522L,61523L,61524L,61525L,61526L,61527L,
95170 61528L,61529L,61530L,61531L,61532L,61533L,61534L,61535L,61536L,61537L,
95171 61538L,61539L,61540L,61541L,61542L,61543L,61544L,61545L,61546L,61547L,
95172 61548L,61549L,61550L,61551L,61552L,61553L,61554L,61555L,61556L,61557L,
95173 61558L,61559L,61560L,61561L,61562L,61563L,61564L,61565L,61566L,61567L,
95174 61568L,61569L,61570L,61571L,61572L,61573L,61574L,61575L,61576L,61577L,
95175 61578L,61579L,61580L,61581L,61582L,61583L,61584L,61585L,61586L,61587L,
95176 61588L,61589L,61590L,61591L,61592L,61593L,61594L,61595L,61596L,61597L,
95177 61598L,61599L,61600L,61601L,61602L,61603L,61604L,61605L,61606L,61607L,
95178 61608L,61609L,61610L,61611L,61612L,61613L,61614L,61615L,61616L,61617L,
95179 61618L,61619L,61620L,61621L,61622L,61623L,61624L,61625L,61626L,61627L,
95180 61628L,61629L,61630L,61631L,61632L,61633L,61634L,61635L,61636L,61637L,
95181 61638L,61639L,61640L,61641L,61642L,61643L,61644L,61645L,61646L,61647L,
95182 61648L,61649L,61650L,61651L,61652L,61653L,61654L,61655L,61656L,61657L,
95183 61658L,61659L,61660L,61661L,61662L,61663L,61664L,61665L,61666L,61667L,
95184 61668L,61669L,61670L,61671L,61672L,61673L,61674L,61675L,61676L,61677L,
95185 61678L,61679L,61680L,61681L,61682L,61683L,61684L,61685L,61686L,61687L,
95186 61688L,61689L,61690L,61691L,61692L,61693L,61694L,61695L,61696L,61697L,
95187 61698L,61699L,61700L,61701L,61702L,61703L,61704L,61705L,61706L,61707L,
95188 61708L,61709L,61710L,61711L,61712L,61713L,61714L,61715L,61716L,61717L,
95189 61718L,61719L,61720L,61721L,61722L,61723L,61724L,61725L,61726L,61727L,
95190 61728L,61729L,61730L,61731L,61732L,61733L,61734L,61735L,61736L,61737L,
95191 61738L,61739L,61740L,61741L,61742L,61743L,61744L,61745L,61746L,61747L,
95192 61748L,61749L,61750L,61751L,61752L,61753L,61754L,61755L,61756L,61757L,
95193 61758L,61759L,61760L,61761L,61762L,61763L,61764L,61765L,61766L,61767L,
95194 61768L,61769L,61770L,61771L,61772L,61773L,61774L,61775L,61776L,61777L,
95195 61778L,61779L,61780L,61781L,61782L,61783L,61784L,61785L,61786L,61787L,
95196 61788L,61789L,61790L,61791L,61792L,61793L,61794L,61795L,61796L,61797L,
95197 61798L,61799L,61800L,61801L,61802L,61803L,61804L,61805L,61806L,61807L,
95198 61808L,61809L,61810L,61811L,61812L,61813L,61814L,61815L,61816L,61817L,
95199 61818L,61819L,61820L,61821L,61822L,61823L,61824L,61825L,61826L,61827L,
95200 61828L,61829L,61830L,61831L,61832L,61833L,61834L,61835L,61836L,61837L,
95201 61838L,61839L,61840L,61841L,61842L,61843L,61844L,61845L,61846L,61847L,
95202 61848L,61849L,61850L,61851L,61852L,61853L,61854L,61855L,61856L,61857L,
95203 61858L,61859L,61860L,61861L,61862L,61863L,61864L,61865L,61866L,61867L,
95204 61868L,61869L,61870L,61871L,61872L,61873L,61874L,61875L,61876L,61877L,
95205 61878L,61879L,61880L,61881L,61882L,61883L,61884L,61885L,61886L,61887L,
95206 61888L,61889L,61890L,61891L,61892L,61893L,61894L,61895L,61896L,61897L,
95207 61898L,61899L,61900L,61901L,61902L,61903L,61904L,61905L,61906L,61907L,
95208 61908L,61909L,61910L,61911L,61912L,61913L,61914L,61915L,61916L,61917L,
95209 61918L,61919L,61920L,61921L,61922L,61923L,61924L,61925L,61926L,61927L,
95210 61928L,61929L,61930L,61931L,61932L,61933L,61934L,61935L,61936L,61937L,
95211 61938L,61939L,61940L,61941L,61942L,61943L,61944L,61945L,61946L,61947L,
95212 61948L,61949L,61950L,61951L,61952L,61953L,61954L,61955L,61956L,61957L,
95213 61958L,61959L,61960L,61961L,61962L,61963L,61964L,61965L,61966L,61967L,
95214 61968L,61969L,61970L,61971L,61972L,61973L,61974L,61975L,61976L,61977L,
95215 61978L,61979L,61980L,61981L,61982L,61983L,61984L,61985L,61986L,61987L,
95216 61988L,61989L,61990L,61991L,61992L,61993L,61994L,61995L,61996L,61997L,
95217 61998L,61999L,62000L,62001L,62002L,62003L,62004L,62005L,62006L,62007L,
95218 62008L,62009L,62010L,62011L,62012L,62013L,62014L,62015L,62016L,62017L,
95219 62018L,62019L,62020L,62021L,62022L,62023L,62024L,62025L,62026L,62027L,
95220 62028L,62029L,62030L,62031L,62032L,62033L,62034L,62035L,62036L,62037L,
95221 62038L,62039L,62040L,62041L,62042L,62043L,62044L,62045L,62046L,62047L,
95222 62048L,62049L,62050L,62051L,62052L,62053L,62054L,62055L,62056L,62057L,
95223 62058L,62059L,62060L,62061L,62062L,62063L,62064L,62065L,62066L,62067L,
95224 62068L,62069L,62070L,62071L,62072L,62073L,62074L,62075L,62076L,62077L,
95225 62078L,62079L,62080L,62081L,62082L,62083L,62084L,62085L,62086L,62087L,
95226 62088L,62089L,62090L,62091L,62092L,62093L,62094L,62095L,62096L,62097L,
95227 62098L,62099L,62100L,62101L,62102L,62103L,62104L,62105L,62106L,62107L,
95228 62108L,62109L,62110L,62111L,62112L,62113L,62114L,62115L,62116L,62117L,
95229 62118L,62119L,62120L,62121L,62122L,62123L,62124L,62125L,62126L,62127L,
95230 62128L,62129L,62130L,62131L,62132L,62133L,62134L,62135L,62136L,62137L,
95231 62138L,62139L,62140L,62141L,62142L,62143L,62144L,62145L,62146L,62147L,
95232 62148L,62149L,62150L,62151L,62152L,62153L,62154L,62155L,62156L,62157L,
95233 62158L,62159L,62160L,62161L,62162L,62163L,62164L,62165L,62166L,62167L,
95234 62168L,62169L,62170L,62171L,62172L,62173L,62174L,62175L,62176L,62177L,
95235 62178L,62179L,62180L,62181L,62182L,62183L,62184L,62185L,62186L,62187L,
95236 62188L,62189L,62190L,62191L,62192L,62193L,62194L,62195L,62196L,62197L,
95237 62198L,62199L,62200L,62201L,62202L,62203L,62204L,62205L,62206L,62207L,
95238 62208L,62209L,62210L,62211L,62212L,62213L,62214L,62215L,62216L,62217L,
95239 62218L,62219L,62220L,62221L,62222L,62223L,62224L,62225L,62226L,62227L,
95240 62228L,62229L,62230L,62231L,62232L,62233L,62234L,62235L,62236L,62237L,
95241 62238L,62239L,62240L,62241L,62242L,62243L,62244L,62245L,62246L,62247L,
95242 62248L,62249L,62250L,62251L,62252L,62253L,62254L,62255L,62256L,62257L,
95243 62258L,62259L,62260L,62261L,62262L,62263L,62264L,62265L,62266L,62267L,
95244 62268L,62269L,62270L,62271L,62272L,62273L,62274L,62275L,62276L,62277L,
95245 62278L,62279L,62280L,62281L,62282L,62283L,62284L,62285L,62286L,62287L,
95246 62288L,62289L,62290L,62291L,62292L,62293L,62294L,62295L,62296L,62297L,
95247 62298L,62299L,62300L,62301L,62302L,62303L,62304L,62305L,62306L,62307L,
95248 62308L,62309L,62310L,62311L,62312L,62313L,62314L,62315L,62316L,62317L,
95249 62318L,62319L,62320L,62321L,62322L,62323L,62324L,62325L,62326L,62327L,
95250 62328L,62329L,62330L,62331L,62332L,62333L,62334L,62335L,62336L,62337L,
95251 62338L,62339L,62340L,62341L,62342L,62343L,62344L,62345L,62346L,62347L,
95252 62348L,62349L,62350L,62351L,62352L,62353L,62354L,62355L,62356L,62357L,
95253 62358L,62359L,62360L,62361L,62362L,62363L,62364L,62365L,62366L,62367L,
95254 62368L,62369L,62370L,62371L,62372L,62373L,62374L,62375L,62376L,62377L,
95255 62378L,62379L,62380L,62381L,62382L,62383L,62384L,62385L,62386L,62387L,
95256 62388L,62389L,62390L,62391L,62392L,62393L,62394L,62395L,62396L,62397L,
95257 62398L,62399L,62400L,62401L,62402L,62403L,62404L,62405L,62406L,62407L,
95258 62408L,62409L,62410L,62411L,62412L,62413L,62414L,62415L,62416L,62417L,
95259 62418L,62419L,62420L,62421L,62422L,62423L,62424L,62425L,62426L,62427L,
95260 62428L,62429L,62430L,62431L,62432L,62433L,62434L,62435L,62436L,62437L,
95261 62438L,62439L,62440L,62441L,62442L,62443L,62444L,62445L,62446L,62447L,
95262 62448L,62449L,62450L,62451L,62452L,62453L,62454L,62455L,62456L,62457L,
95263 62458L,62459L,62460L,62461L,62462L,62463L,62464L,62465L,62466L,62467L,
95264 62468L,62469L,62470L,62471L,62472L,62473L,62474L,62475L,62476L,62477L,
95265 62478L,62479L,62480L,62481L,62482L,62483L,62484L,62485L,62486L,62487L,
95266 62488L,62489L,62490L,62491L,62492L,62493L,62494L,62495L,62496L,62497L,
95267 62498L,62499L,62500L,62501L,62502L,62503L,62504L,62505L,62506L,62507L,
95268 62508L,62509L,62510L,62511L,62512L,62513L,62514L,62515L,62516L,62517L,
95269 62518L,62519L,62520L,62521L,62522L,62523L,62524L,62525L,62526L,62527L,
95270 62528L,62529L,62530L,62531L,62532L,62533L,62534L,62535L,62536L,62537L,
95271 62538L,62539L,62540L,62541L,62542L,62543L,62544L,62545L,62546L,62547L,
95272 62548L,62549L,62550L,62551L,62552L,62553L,62554L,62555L,62556L,62557L,
95273 62558L,62559L,62560L,62561L,62562L,62563L,62564L,62565L,62566L,62567L,
95274 62568L,62569L,62570L,62571L,62572L,62573L,62574L,62575L,62576L,62577L,
95275 62578L,62579L,62580L,62581L,62582L,62583L,62584L,62585L,62586L,62587L,
95276 62588L,62589L,62590L,62591L,62592L,62593L,62594L,62595L,62596L,62597L,
95277 62598L,62599L,62600L,62601L,62602L,62603L,62604L,62605L,62606L,62607L,
95278 62608L,62609L,62610L,62611L,62612L,62613L,62614L,62615L,62616L,62617L,
95279 62618L,62619L,62620L,62621L,62622L,62623L,62624L,62625L,62626L,62627L,
95280 62628L,62629L,62630L,62631L,62632L,62633L,62634L,62635L,62636L,62637L,
95281 62638L,62639L,62640L,62641L,62642L,62643L,62644L,62645L,62646L,62647L,
95282 62648L,62649L,62650L,62651L,62652L,62653L,62654L,62655L,62656L,62657L,
95283 62658L,62659L,62660L,62661L,62662L,62663L,62664L,62665L,62666L,62667L,
95284 62668L,62669L,62670L,62671L,62672L,62673L,62674L,62675L,62676L,62677L,
95285 62678L,62679L,62680L,62681L,62682L,62683L,62684L,62685L,62686L,62687L,
95286 62688L,62689L,62690L,62691L,62692L,62693L,62694L,62695L,62696L,62697L,
95287 62698L,62699L,62700L,62701L,62702L,62703L,62704L,62705L,62706L,62707L,
95288 62708L,62709L,62710L,62711L,62712L,62713L,62714L,62715L,62716L,62717L,
95289 62718L,62719L,62720L,62721L,62722L,62723L,62724L,62725L,62726L,62727L,
95290 62728L,62729L,62730L,62731L,62732L,62733L,62734L,62735L,62736L,62737L,
95291 62738L,62739L,62740L,62741L,62742L,62743L,62744L,62745L,62746L,62747L,
95292 62748L,62749L,62750L,62751L,62752L,62753L,62754L,62755L,62756L,62757L,
95293 62758L,62759L,62760L,62761L,62762L,62763L,62764L,62765L,62766L,62767L,
95294 62768L,62769L,62770L,62771L,62772L,62773L,62774L,62775L,62776L,62777L,
95295 62778L,62779L,62780L,62781L,62782L,62783L,62784L,62785L,62786L,62787L,
95296 62788L,62789L,62790L,62791L,62792L,62793L,62794L,62795L,62796L,62797L,
95297 62798L,62799L,62800L,62801L,62802L,62803L,62804L,62805L,62806L,62807L,
95298 62808L,62809L,62810L,62811L,62812L,62813L,62814L,62815L,62816L,62817L,
95299 62818L,62819L,62820L,62821L,62822L,62823L,62824L,62825L,62826L,62827L,
95300 62828L,62829L,62830L,62831L,62832L,62833L,62834L,62835L,62836L,62837L,
95301 62838L,62839L,62840L,62841L,62842L,62843L,62844L,62845L,62846L,62847L,
95302 62848L,62849L,62850L,62851L,62852L,62853L,62854L,62855L,62856L,62857L,
95303 62858L,62859L,62860L,62861L,62862L,62863L,62864L,62865L,62866L,62867L,
95304 62868L,62869L,62870L,62871L,62872L,62873L,62874L,62875L,62876L,62877L,
95305 62878L,62879L,62880L,62881L,62882L,62883L,62884L,62885L,62886L,62887L,
95306 62888L,62889L,62890L,62891L,62892L,62893L,62894L,62895L,62896L,62897L,
95307 62898L,62899L,62900L,62901L,62902L,62903L,62904L,62905L,62906L,62907L,
95308 62908L,62909L,62910L,62911L,62912L,62913L,62914L,62915L,62916L,62917L,
95309 62918L,62919L,62920L,62921L,62922L,62923L,62924L,62925L,62926L,62927L,
95310 62928L,62929L,62930L,62931L,62932L,62933L,62934L,62935L,62936L,62937L,
95311 62938L,62939L,62940L,62941L,62942L,62943L,62944L,62945L,62946L,62947L,
95312 62948L,62949L,62950L,62951L,62952L,62953L,62954L,62955L,62956L,62957L,
95313 62958L,62959L,62960L,62961L,62962L,62963L,62964L,62965L,62966L,62967L,
95314 62968L,62969L,62970L,62971L,62972L,62973L,62974L,62975L,62976L,62977L,
95315 62978L,62979L,62980L,62981L,62982L,62983L,62984L,62985L,62986L,62987L,
95316 62988L,62989L,62990L,62991L,62992L,62993L,62994L,62995L,62996L,62997L,
95317 62998L,62999L,63000L,63001L,63002L,63003L,63004L,63005L,63006L,63007L,
95318 63008L,63009L,63010L,63011L,63012L,63013L,63014L,63015L,63016L,63017L,
95319 63018L,63019L,63020L,63021L,63022L,63023L,63024L,63025L,63026L,63027L,
95320 63028L,63029L,63030L,63031L,63032L,63033L,63034L,63035L,63036L,63037L,
95321 63038L,63039L,63040L,63041L,63042L,63043L,63044L,63045L,63046L,63047L,
95322 63048L,63049L,63050L,63051L,63052L,63053L,63054L,63055L,63056L,63057L,
95323 63058L,63059L,63060L,63061L,63062L,63063L,63064L,63065L,63066L,63067L,
95324 63068L,63069L,63070L,63071L,63072L,63073L,63074L,63075L,63076L,63077L,
95325 63078L,63079L,63080L,63081L,63082L,63083L,63084L,63085L,63086L,63087L,
95326 63088L,63089L,63090L,63091L,63092L,63093L,63094L,63095L,63096L,63097L,
95327 63098L,63099L,63100L,63101L,63102L,63103L,63104L,63105L,63106L,63107L,
95328 63108L,63109L,63110L,63111L,63112L,63113L,63114L,63115L,63116L,63117L,
95329 63118L,63119L,63120L,63121L,63122L,63123L,63124L,63125L,63126L,63127L,
95330 63128L,63129L,63130L,63131L,63132L,63133L,63134L,63135L,63136L,63137L,
95331 63138L,63139L,63140L,63141L,63142L,63143L,63144L,63145L,63146L,63147L,
95332 63148L,63149L,63150L,63151L,63152L,63153L,63154L,63155L,63156L,63157L,
95333 63158L,63159L,63160L,63161L,63162L,63163L,63164L,63165L,63166L,63167L,
95334 63168L,63169L,63170L,63171L,63172L,63173L,63174L,63175L,63176L,63177L,
95335 63178L,63179L,63180L,63181L,63182L,63183L,63184L,63185L,63186L,63187L,
95336 63188L,63189L,63190L,63191L,63192L,63193L,63194L,63195L,63196L,63197L,
95337 63198L,63199L,63200L,63201L,63202L,63203L,63204L,63205L,63206L,63207L,
95338 63208L,63209L,63210L,63211L,63212L,63213L,63214L,63215L,63216L,63217L,
95339 63218L,63219L,63220L,63221L,63222L,63223L,63224L,63225L,63226L,63227L,
95340 63228L,63229L,63230L,63231L,63232L,63233L,63234L,63235L,63236L,63237L,
95341 63238L,63239L,63240L,63241L,63242L,63243L,63244L,63245L,63246L,63247L,
95342 63248L,63249L,63250L,63251L,63252L,63253L,63254L,63255L,63256L,63257L,
95343 63258L,63259L,63260L,63261L,63262L,63263L,63264L,63265L,63266L,63267L,
95344 63268L,63269L,63270L,63271L,63272L,63273L,63274L,63275L,63276L,63277L,
95345 63278L,63279L,63280L,63281L,63282L,63283L,63284L,63285L,63286L,63287L,
95346 63288L,63289L,63290L,63291L,63292L,63293L,63294L,63295L,63296L,63297L,
95347 63298L,63299L,63300L,63301L,63302L,63303L,63304L,63305L,63306L,63307L,
95348 63308L,63309L,63310L,63311L,63312L,63313L,63314L,63315L,63316L,63317L,
95349 63318L,63319L,63320L,63321L,63322L,63323L,63324L,63325L,63326L,63327L,
95350 63328L,63329L,63330L,63331L,63332L,63333L,63334L,63335L,63336L,63337L,
95351 63338L,63339L,63340L,63341L,63342L,63343L,63344L,63345L,63346L,63347L,
95352 63348L,63349L,63350L,63351L,63352L,63353L,63354L,63355L,63356L,63357L,
95353 63358L,63359L,63360L,63361L,63362L,63363L,63364L,63365L,63366L,63367L,
95354 63368L,63369L,63370L,63371L,63372L,63373L,63374L,63375L,63376L,63377L,
95355 63378L,63379L,63380L,63381L,63382L,63383L,63384L,63385L,63386L,63387L,
95356 63388L,63389L,63390L,63391L,63392L,63393L,63394L,63395L,63396L,63397L,
95357 63398L,63399L,63400L,63401L,63402L,63403L,63404L,63405L,63406L,63407L,
95358 63408L,63409L,63410L,63411L,63412L,63413L,63414L,63415L,63416L,63417L,
95359 63418L,63419L,63420L,63421L,63422L,63423L,63424L,63425L,63426L,63427L,
95360 63428L,63429L,63430L,63431L,63432L,63433L,63434L,63435L,63436L,63437L,
95361 63438L,63439L,63440L,63441L,63442L,63443L,63444L,63445L,63446L,63447L,
95362 63448L,63449L,63450L,63451L,63452L,63453L,63454L,63455L,63456L,63457L,
95363 63458L,63459L,63460L,63461L,63462L,63463L,63464L,63465L,63466L,63467L,
95364 63468L,63469L,63470L,63471L,63472L,63473L,63474L,63475L,63476L,63477L,
95365 63478L,63479L,63480L,63481L,63482L,63483L,63484L,63485L,63486L,63487L,
95366 63488L,63489L,63490L,63491L,63492L,63493L,63494L,63495L,63496L,63497L,
95367 63498L,63499L,63500L,63501L,63502L,63503L,63504L,63505L,63506L,63507L,
95368 63508L,63509L,63510L,63511L,63512L,63513L,63514L,63515L,63516L,63517L,
95369 63518L,63519L,63520L,63521L,63522L,63523L,63524L,63525L,63526L,63527L,
95370 63528L,63529L,63530L,63531L,63532L,63533L,63534L,63535L,63536L,63537L,
95371 63538L,63539L,63540L,63541L,63542L,63543L,63544L,63545L,63546L,63547L,
95372 63548L,63549L,63550L,63551L,63552L,63553L,63554L,63555L,63556L,63557L,
95373 63558L,63559L,63560L,63561L,63562L,63563L,63564L,63565L,63566L,63567L,
95374 63568L,63569L,63570L,63571L,63572L,63573L,63574L,63575L,63576L,63577L,
95375 63578L,63579L,63580L,63581L,63582L,63583L,63584L,63585L,63586L,63587L,
95376 63588L,63589L,63590L,63591L,63592L,63593L,63594L,63595L,63596L,63597L,
95377 63598L,63599L,63600L,63601L,63602L,63603L,63604L,63605L,63606L,63607L,
95378 63608L,63609L,63610L,63611L,63612L,63613L,63614L,63615L,63616L,63617L,
95379 63618L,63619L,63620L,63621L,63622L,63623L,63624L,63625L,63626L,63627L,
95380 63628L,63629L,63630L,63631L,63632L,63633L,63634L,63635L,63636L,63637L,
95381 63638L,63639L,63640L,63641L,63642L,63643L,63644L,63645L,63646L,63647L,
95382 63648L,63649L,63650L,63651L,63652L,63653L,63654L,63655L,63656L,63657L,
95383 63658L,63659L,63660L,63661L,63662L,63663L,63664L,63665L,63666L,63667L,
95384 63668L,63669L,63670L,63671L,63672L,63673L,63674L,63675L,63676L,63677L,
95385 63678L,63679L,63680L,63681L,63682L,63683L,63684L,63685L,63686L,63687L,
95386 63688L,63689L,63690L,63691L,63692L,63693L,63694L,63695L,63696L,63697L,
95387 63698L,63699L,63700L,63701L,63702L,63703L,63704L,63705L,63706L,63707L,
95388 63708L,63709L,63710L,63711L,63712L,63713L,63714L,63715L,63716L,63717L,
95389 63718L,63719L,63720L,63721L,63722L,63723L,63724L,63725L,63726L,63727L,
95390 63728L,63729L,63730L,63731L,63732L,63733L,63734L,63735L,63736L,63737L,
95391 63738L,63739L,63740L,63741L,63742L,63743L,63744L,63745L,63746L,63747L,
95392 63748L,63749L,63750L,63751L,63752L,63753L,63754L,63755L,63756L,63757L,
95393 63758L,63759L,63760L,63761L,63762L,63763L,63764L,63765L,63766L,63767L,
95394 63768L,63769L,63770L,63771L,63772L,63773L,63774L,63775L,63776L,63777L,
95395 63778L,63779L,63780L,63781L,63782L,63783L,63784L,63785L,63786L,63787L,
95396 63788L,63789L,63790L,63791L,63792L,63793L,63794L,63795L,63796L,63797L,
95397 63798L,63799L,63800L,63801L,63802L,63803L,63804L,63805L,63806L,63807L,
95398 63808L,63809L,63810L,63811L,63812L,63813L,63814L,63815L,63816L,63817L,
95399 63818L,63819L,63820L,63821L,63822L,63823L,63824L,63825L,63826L,63827L,
95400 63828L,63829L,63830L,63831L,63832L,63833L,63834L,63835L,63836L,63837L,
95401 63838L,63839L,63840L,63841L,63842L,63843L,63844L,63845L,63846L,63847L,
95402 63848L,63849L,63850L,63851L,63852L,63853L,63854L,63855L,63856L,63857L,
95403 63858L,63859L,63860L,63861L,63862L,63863L,63864L,63865L,63866L,63867L,
95404 63868L,63869L,63870L,63871L,63872L,63873L,63874L,63875L,63876L,63877L,
95405 63878L,63879L,63880L,63881L,63882L,63883L,63884L,63885L,63886L,63887L,
95406 63888L,63889L,63890L,63891L,63892L,63893L,63894L,63895L,63896L,63897L,
95407 63898L,63899L,63900L,63901L,63902L,63903L,63904L,63905L,63906L,63907L,
95408 63908L,63909L,63910L,63911L,63912L,63913L,63914L,63915L,63916L,63917L,
95409 63918L,63919L,63920L,63921L,63922L,63923L,63924L,63925L,63926L,63927L,
95410 63928L,63929L,63930L,63931L,63932L,63933L,63934L,63935L,63936L,63937L,
95411 63938L,63939L,63940L,63941L,63942L,63943L,63944L,63945L,63946L,63947L,
95412 63948L,63949L,63950L,63951L,63952L,63953L,63954L,63955L,63956L,63957L,
95413 63958L,63959L,63960L,63961L,63962L,63963L,63964L,63965L,63966L,63967L,
95414 63968L,63969L,63970L,63971L,63972L,63973L,63974L,63975L,63976L,63977L,
95415 63978L,63979L,63980L,63981L,63982L,63983L,63984L,63985L,63986L,63987L,
95416 63988L,63989L,63990L,63991L,63992L,63993L,63994L,63995L,63996L,63997L,
95417 63998L,63999L,64000L,64001L,64002L,64003L,64004L,64005L,64006L,64007L,
95418 64008L,64009L,64010L,64011L,64012L,64013L,64014L,64015L,64016L,64017L,
95419 64018L,64019L,64020L,64021L,64022L,64023L,64024L,64025L,64026L,64027L,
95420 64028L,64029L,64030L,64031L,64032L,64033L,64034L,64035L,64036L,64037L,
95421 64038L,64039L,64040L,64041L,64042L,64043L,64044L,64045L,64046L,64047L,
95422 64048L,64049L,64050L,64051L,64052L,64053L,64054L,64055L,64056L,64057L,
95423 64058L,64059L,64060L,64061L,64062L,64063L,64064L,64065L,64066L,64067L,
95424 64068L,64069L,64070L,64071L,64072L,64073L,64074L,64075L,64076L,64077L,
95425 64078L,64079L,64080L,64081L,64082L,64083L,64084L,64085L,64086L,64087L,
95426 64088L,64089L,64090L,64091L,64092L,64093L,64094L,64095L,64096L,64097L,
95427 64098L,64099L,64100L,64101L,64102L,64103L,64104L,64105L,64106L,64107L,
95428 64108L,64109L,64110L,64111L,64112L,64113L,64114L,64115L,64116L,64117L,
95429 64118L,64119L,64120L,64121L,64122L,64123L,64124L,64125L,64126L,64127L,
95430 64128L,64129L,64130L,64131L,64132L,64133L,64134L,64135L,64136L,64137L,
95431 64138L,64139L,64140L,64141L,64142L,64143L,64144L,64145L,64146L,64147L,
95432 64148L,64149L,64150L,64151L,64152L,64153L,64154L,64155L,64156L,64157L,
95433 64158L,64159L,64160L,64161L,64162L,64163L,64164L,64165L,64166L,64167L,
95434 64168L,64169L,64170L,64171L,64172L,64173L,64174L,64175L,64176L,64177L,
95435 64178L,64179L,64180L,64181L,64182L,64183L,64184L,64185L,64186L,64187L,
95436 64188L,64189L,64190L,64191L,64192L,64193L,64194L,64195L,64196L,64197L,
95437 64198L,64199L,64200L,64201L,64202L,64203L,64204L,64205L,64206L,64207L,
95438 64208L,64209L,64210L,64211L,64212L,64213L,64214L,64215L,64216L,64217L,
95439 64218L,64219L,64220L,64221L,64222L,64223L,64224L,64225L,64226L,64227L,
95440 64228L,64229L,64230L,64231L,64232L,64233L,64234L,64235L,64236L,64237L,
95441 64238L,64239L,64240L,64241L,64242L,64243L,64244L,64245L,64246L,64247L,
95442 64248L,64249L,64250L,64251L,64252L,64253L,64254L,64255L,64256L,64257L,
95443 64258L,64259L,64260L,64261L,64262L,64263L,64264L,64265L,64266L,64267L,
95444 64268L,64269L,64270L,64271L,64272L,64273L,64274L,64275L,64276L,64277L,
95445 64278L,64279L,64280L,64281L,64282L,64283L,64284L,64285L,64286L,64287L,
95446 64288L,64289L,64290L,64291L,64292L,64293L,64294L,64295L,64296L,64297L,
95447 64298L,64299L,64300L,64301L,64302L,64303L,64304L,64305L,64306L,64307L,
95448 64308L,64309L,64310L,64311L,64312L,64313L,64314L,64315L,64316L,64317L,
95449 64318L,64319L,64320L,64321L,64322L,64323L,64324L,64325L,64326L,64327L,
95450 64328L,64329L,64330L,64331L,64332L,64333L,64334L,64335L,64336L,64337L,
95451 64338L,64339L,64340L,64341L,64342L,64343L,64344L,64345L,64346L,64347L,
95452 64348L,64349L,64350L,64351L,64352L,64353L,64354L,64355L,64356L,64357L,
95453 64358L,64359L,64360L,64361L,64362L,64363L,64364L,64365L,64366L,64367L,
95454 64368L,64369L,64370L,64371L,64372L,64373L,64374L,64375L,64376L,64377L,
95455 64378L,64379L,64380L,64381L,64382L,64383L,64384L,64385L,64386L,64387L,
95456 64388L,64389L,64390L,64391L,64392L,64393L,64394L,64395L,64396L,64397L,
95457 64398L,64399L,64400L,64401L,64402L,64403L,64404L,64405L,64406L,64407L,
95458 64408L,64409L,64410L,64411L,64412L,64413L,64414L,64415L,64416L,64417L,
95459 64418L,64419L,64420L,64421L,64422L,64423L,64424L,64425L,64426L,64427L,
95460 64428L,64429L,64430L,64431L,64432L,64433L,64434L,64435L,64436L,64437L,
95461 64438L,64439L,64440L,64441L,64442L,64443L,64444L,64445L,64446L,64447L,
95462 64448L,64449L,64450L,64451L,64452L,64453L,64454L,64455L,64456L,64457L,
95463 64458L,64459L,64460L,64461L,64462L,64463L,64464L,64465L,64466L,64467L,
95464 64468L,64469L,64470L,64471L,64472L,64473L,64474L,64475L,64476L,64477L,
95465 64478L,64479L,64480L,64481L,64482L,64483L,64484L,64485L,64486L,64487L,
95466 64488L,64489L,64490L,64491L,64492L,64493L,64494L,64495L,64496L,64497L,
95467 64498L,64499L,64500L,64501L,64502L,64503L,64504L,64505L,64506L,64507L,
95468 64508L,64509L,64510L,64511L,64512L,64513L,64514L,64515L,64516L,64517L,
95469 64518L,64519L,64520L,64521L,64522L,64523L,64524L,64525L,64526L,64527L,
95470 64528L,64529L,64530L,64531L,64532L,64533L,64534L,64535L,64536L,64537L,
95471 64538L,64539L,64540L,64541L,64542L,64543L,64544L,64545L,64546L,64547L,
95472 64548L,64549L,64550L,64551L,64552L,64553L,64554L,64555L,64556L,64557L,
95473 64558L,64559L,64560L,64561L,64562L,64563L,64564L,64565L,64566L,64567L,
95474 64568L,64569L,64570L,64571L,64572L,64573L,64574L,64575L,64576L,64577L,
95475 64578L,64579L,64580L,64581L,64582L,64583L,64584L,64585L,64586L,64587L,
95476 64588L,64589L,64590L,64591L,64592L,64593L,64594L,64595L,64596L,64597L,
95477 64598L,64599L,64600L,64601L,64602L,64603L,64604L,64605L,64606L,64607L,
95478 64608L,64609L,64610L,64611L,64612L,64613L,64614L,64615L,64616L,64617L,
95479 64618L,64619L,64620L,64621L,64622L,64623L,64624L,64625L,64626L,64627L,
95480 64628L,64629L,64630L,64631L,64632L,64633L,64634L,64635L,64636L,64637L,
95481 64638L,64639L,64640L,64641L,64642L,64643L,64644L,64645L,64646L,64647L,
95482 64648L,64649L,64650L,64651L,64652L,64653L,64654L,64655L,64656L,64657L,
95483 64658L,64659L,64660L,64661L,64662L,64663L,64664L,64665L,64666L,64667L,
95484 64668L,64669L,64670L,64671L,64672L,64673L,64674L,64675L,64676L,64677L,
95485 64678L,64679L,64680L,64681L,64682L,64683L,64684L,64685L,64686L,64687L,
95486 64688L,64689L,64690L,64691L,64692L,64693L,64694L,64695L,64696L,64697L,
95487 64698L,64699L,64700L,64701L,64702L,64703L,64704L,64705L,64706L,64707L,
95488 64708L,64709L,64710L,64711L,64712L,64713L,64714L,64715L,64716L,64717L,
95489 64718L,64719L,64720L,64721L,64722L,64723L,64724L,64725L,64726L,64727L,
95490 64728L,64729L,64730L,64731L,64732L,64733L,64734L,64735L,64736L,64737L,
95491 64738L,64739L,64740L,64741L,64742L,64743L,64744L,64745L,64746L,64747L,
95492 64748L,64749L,64750L,64751L,64752L,64753L,64754L,64755L,64756L,64757L,
95493 64758L,64759L,64760L,64761L,64762L,64763L,64764L,64765L,64766L,64767L,
95494 64768L,64769L,64770L,64771L,64772L,64773L,64774L,64775L,64776L,64777L,
95495 64778L,64779L,64780L,64781L,64782L,64783L,64784L,64785L,64786L,64787L,
95496 64788L,64789L,64790L,64791L,64792L,64793L,64794L,64795L,64796L,64797L,
95497 64798L,64799L,64800L,64801L,64802L,64803L,64804L,64805L,64806L,64807L,
95498 64808L,64809L,64810L,64811L,64812L,64813L,64814L,64815L,64816L,64817L,
95499 64818L,64819L,64820L,64821L,64822L,64823L,64824L,64825L,64826L,64827L,
95500 64828L,64829L,64830L,64831L,64832L,64833L,64834L,64835L,64836L,64837L,
95501 64838L,64839L,64840L,64841L,64842L,64843L,64844L,64845L,64846L,64847L,
95502 64848L,64849L,64850L,64851L,64852L,64853L,64854L,64855L,64856L,64857L,
95503 64858L,64859L,64860L,64861L,64862L,64863L,64864L,64865L,64866L,64867L,
95504 64868L,64869L,64870L,64871L,64872L,64873L,64874L,64875L,64876L,64877L,
95505 64878L,64879L,64880L,64881L,64882L,64883L,64884L,64885L,64886L,64887L,
95506 64888L,64889L,64890L,64891L,64892L,64893L,64894L,64895L,64896L,64897L,
95507 64898L,64899L,64900L,64901L,64902L,64903L,64904L,64905L,64906L,64907L,
95508 64908L,64909L,64910L,64911L,64912L,64913L,64914L,64915L,64916L,64917L,
95509 64918L,64919L,64920L,64921L,64922L,64923L,64924L,64925L,64926L,64927L,
95510 64928L,64929L,64930L,64931L,64932L,64933L,64934L,64935L,64936L,64937L,
95511 64938L,64939L,64940L,64941L,64942L,64943L,64944L,64945L,64946L,64947L,
95512 64948L,64949L,64950L,64951L,64952L,64953L,64954L,64955L,64956L,64957L,
95513 64958L,64959L,64960L,64961L,64962L,64963L,64964L,64965L,64966L,64967L,
95514 64968L,64969L,64970L,64971L,64972L,64973L,64974L,64975L,64976L,64977L,
95515 64978L,64979L,64980L,64981L,64982L,64983L,64984L,64985L,64986L,64987L,
95516 64988L,64989L,64990L,64991L,64992L,64993L,64994L,64995L,64996L,64997L,
95517 64998L,64999L,65000L,65001L,65002L,65003L,65004L,65005L,65006L,65007L,
95518 65008L,65009L,65010L,65011L,65012L,65013L,65014L,65015L,65016L,65017L,
95519 65018L,65019L,65020L,65021L,65022L,65023L,65024L,65025L,65026L,65027L,
95520 65028L,65029L,65030L,65031L,65032L,65033L,65034L,65035L,65036L,65037L,
95521 65038L,65039L,65040L,65041L,65042L,65043L,65044L,65045L,65046L,65047L,
95522 65048L,65049L,65050L,65051L,65052L,65053L,65054L,65055L,65056L,65057L,
95523 65058L,65059L,65060L,65061L,65062L,65063L,65064L,65065L,65066L,65067L,
95524 65068L,65069L,65070L,65071L,65072L,65073L,65074L,65075L,65076L,65077L,
95525 65078L,65079L,65080L,65081L,65082L,65083L,65084L,65085L,65086L,65087L,
95526 65088L,65089L,65090L,65091L,65092L,65093L,65094L,65095L,65096L,65097L,
95527 65098L,65099L,65100L,65101L,65102L,65103L,65104L,65105L,65106L,65107L,
95528 65108L,65109L,65110L,65111L,65112L,65113L,65114L,65115L,65116L,65117L,
95529 65118L,65119L,65120L,65121L,65122L,65123L,65124L,65125L,65126L,65127L,
95530 65128L,65129L,65130L,65131L,65132L,65133L,65134L,65135L,65136L,65137L,
95531 65138L,65139L,65140L,65141L,65142L,65143L,65144L,65145L,65146L,65147L,
95532 65148L,65149L,65150L,65151L,65152L,65153L,65154L,65155L,65156L,65157L,
95533 65158L,65159L,65160L,65161L,65162L,65163L,65164L,65165L,65166L,65167L,
95534 65168L,65169L,65170L,65171L,65172L,65173L,65174L,65175L,65176L,65177L,
95535 65178L,65179L,65180L,65181L,65182L,65183L,65184L,65185L,65186L,65187L,
95536 65188L,65189L,65190L,65191L,65192L,65193L,65194L,65195L,65196L,65197L,
95537 65198L,65199L,65200L,65201L,65202L,65203L,65204L,65205L,65206L,65207L,
95538 65208L,65209L,65210L,65211L,65212L,65213L,65214L,65215L,65216L,65217L,
95539 65218L,65219L,65220L,65221L,65222L,65223L,65224L,65225L,65226L,65227L,
95540 65228L,65229L,65230L,65231L,65232L,65233L,65234L,65235L,65236L,65237L,
95541 65238L,65239L,65240L,65241L,65242L,65243L,65244L,65245L,65246L,65247L,
95542 65248L,65249L,65250L,65251L,65252L,65253L,65254L,65255L,65256L,65257L,
95543 65258L,65259L,65260L,65261L,65262L,65263L,65264L,65265L,65266L,65267L,
95544 65268L,65269L,65270L,65271L,65272L,65273L,65274L,65275L,65276L,65277L,
95545 65278L,65279L,65280L,65281L,65282L,65283L,65284L,65285L,65286L,65287L,
95546 65288L,65289L,65290L,65291L,65292L,65293L,65294L,65295L,65296L,65297L,
95547 65298L,65299L,65300L,65301L,65302L,65303L,65304L,65305L,65306L,65307L,
95548 65308L,65309L,65310L,65311L,65312L,65313L,65314L,65315L,65316L,65317L,
95549 65318L,65319L,65320L,65321L,65322L,65323L,65324L,65325L,65326L,65327L,
95550 65328L,65329L,65330L,65331L,65332L,65333L,65334L,65335L,65336L,65337L,
95551 65338L,65339L,65340L,65341L,65342L,65343L,65344L,65313L,65314L,65315L,
95552 65316L,65317L,65318L,65319L,65320L,65321L,65322L,65323L,65324L,65325L,
95553 65326L,65327L,65328L,65329L,65330L,65331L,65332L,65333L,65334L,65335L,
95554 65336L,65337L,65338L,65371L,65372L,65373L,65374L,65375L,65376L,65377L,
95555 65378L,65379L,65380L,65381L,65382L,65383L,65384L,65385L,65386L,65387L,
95556 65388L,65389L,65390L,65391L,65392L,65393L,65394L,65395L,65396L,65397L,
95557 65398L,65399L,65400L,65401L,65402L,65403L,65404L,65405L,65406L,65407L,
95558 65408L,65409L,65410L,65411L,65412L,65413L,65414L,65415L,65416L,65417L,
95559 65418L,65419L,65420L,65421L,65422L,65423L,65424L,65425L,65426L,65427L,
95560 65428L,65429L,65430L,65431L,65432L,65433L,65434L,65435L,65436L,65437L,
95561 65438L,65439L,65440L,65441L,65442L,65443L,65444L,65445L,65446L,65447L,
95562 65448L,65449L,65450L,65451L,65452L,65453L,65454L,65455L,65456L,65457L,
95563 65458L,65459L,65460L,65461L,65462L,65463L,65464L,65465L,65466L,65467L,
95564 65468L,65469L,65470L,65471L,65472L,65473L,65474L,65475L,65476L,65477L,
95565 65478L,65479L,65480L,65481L,65482L,65483L,65484L,65485L,65486L,65487L,
95566 65488L,65489L,65490L,65491L,65492L,65493L,65494L,65495L,65496L,65497L,
95567 65498L,65499L,65500L,65501L,65502L,65503L,65504L,65505L,65506L,65507L,
95568 65508L,65509L,65510L,65511L,65512L,65513L,65514L,65515L,65516L,65517L,
95569 65518L,65519L,65520L,65521L,65522L,65523L,65524L,65525L,65526L,65527L,
95570 65528L,65529L,65530L,65531L,65532L,65533L,65534L,65535L,
95571 };
95572 #endif
95573
95574 #if defined(DUK_USE_REGEXP_CANON_BITMAP)
95575 /*
95576  *  Automatically generated by extract_caseconv.py, do not edit!
95577  */
95578
95579 const duk_uint8_t duk_unicode_re_canon_bitmap[256] = {
95580 23,0,224,19,1,228,255,255,255,255,255,255,255,255,255,255,255,255,255,127,
95581 255,255,255,255,255,255,255,255,231,247,0,16,255,227,255,255,63,255,255,
95582 255,255,255,255,255,1,252,255,255,255,255,255,255,255,255,255,255,255,255,
95583 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95584 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95585 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95586 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95587 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95588 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95589 227,193,255,255,255,147,255,255,255,255,255,255,255,255,255,255,255,255,
95590 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95591 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95592 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
95593 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,251,
95594 };
95595 #endif
95596 #line 1 "duk_util_bitdecoder.c"
95597 /*
95598  *  Bitstream decoder.
95599  */
95600
95601 /* #include duk_internal.h -> already included */
95602
95603 /* Decode 'bits' bits from the input stream (bits must be 1...24).
95604  * When reading past bitstream end, zeroes are shifted in.  The result
95605  * is signed to match duk_bd_decode_flagged.
95606  */
95607 DUK_INTERNAL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
95608         duk_small_int_t shift;
95609         duk_uint32_t mask;
95610         duk_uint32_t tmp;
95611
95612         /* Note: cannot read more than 24 bits without possibly shifting top bits out.
95613          * Fixable, but adds complexity.
95614          */
95615         DUK_ASSERT(bits >= 1 && bits <= 24);
95616
95617         while (ctx->currbits < bits) {
95618 #if 0
95619                 DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)",
95620                                      (long) bits, (long) ctx->currbits));
95621 #endif
95622                 ctx->currval <<= 8;
95623                 if (ctx->offset < ctx->length) {
95624                         /* If ctx->offset >= ctx->length, we "shift zeroes in"
95625                          * instead of croaking.
95626                          */
95627                         ctx->currval |= ctx->data[ctx->offset++];
95628                 }
95629                 ctx->currbits += 8;
95630         }
95631 #if 0
95632         DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx",
95633                              (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval));
95634 #endif
95635
95636         /* Extract 'top' bits of currval; note that the extracted bits do not need
95637          * to be cleared, we just ignore them on next round.
95638          */
95639         shift = ctx->currbits - bits;
95640         mask = (((duk_uint32_t) 1U) << bits) - 1U;
95641         tmp = (ctx->currval >> shift) & mask;
95642         ctx->currbits = shift;  /* remaining */
95643
95644 #if 0
95645         DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx",
95646                              (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval));
95647 #endif
95648
95649         return tmp;
95650 }
95651
95652 DUK_INTERNAL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
95653         return (duk_small_uint_t) duk_bd_decode(ctx, 1);
95654 }
95655
95656 /* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
95657  * default value.
95658  */
95659 DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) {
95660         if (duk_bd_decode_flag(ctx)) {
95661                 return duk_bd_decode(ctx, bits);
95662         } else {
95663                 return def_value;
95664         }
95665 }
95666
95667 /* Signed variant, allows negative marker value. */
95668 DUK_INTERNAL duk_int32_t duk_bd_decode_flagged_signed(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
95669         return (duk_int32_t) duk_bd_decode_flagged(ctx, bits, (duk_uint32_t) def_value);
95670 }
95671
95672 /* Shared varint encoding.  Match dukutil.py BitEncode.varuint(). */
95673 DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) {
95674         duk_small_uint_t t;
95675
95676         /* The bit encoding choices here are based on manual testing against
95677          * the actual varuints generated by genbuiltins.py.
95678          */
95679         switch (duk_bd_decode(ctx, 2)) {
95680         case 0:
95681                 return 0;  /* [0,0] */
95682         case 1:
95683                 return duk_bd_decode(ctx, 2) + 1;  /* [1,4] */
95684         case 2:
95685                 return duk_bd_decode(ctx, 5) + 5;  /* [5,36] */
95686         default:
95687                 t = duk_bd_decode(ctx, 7);
95688                 if (t == 0) {
95689                         return duk_bd_decode(ctx, 20);
95690                 }
95691                 return (t - 1) + 37;  /* [37,163] */
95692         }
95693 }
95694
95695 /* Decode a bit packed string from a custom format used by genbuiltins.py.
95696  * This function is here because it's used for both heap and thread inits.
95697  * Caller must supply the output buffer whose size is NOT checked!
95698  */
95699
95700 #define DUK__BITPACK_LETTER_LIMIT  26
95701 #define DUK__BITPACK_LOOKUP1       26
95702 #define DUK__BITPACK_LOOKUP2       27
95703 #define DUK__BITPACK_SWITCH1       28
95704 #define DUK__BITPACK_SWITCH        29
95705 #define DUK__BITPACK_UNUSED1       30
95706 #define DUK__BITPACK_EIGHTBIT      31
95707
95708 DUK_LOCAL const duk_uint8_t duk__bitpacked_lookup[16] = {
95709         DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
95710         DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
95711         DUK_ASC_8, DUK_ASC_9, DUK_ASC_UNDERSCORE, DUK_ASC_SPACE,
95712         0x82, 0x80, DUK_ASC_DOUBLEQUOTE, DUK_ASC_LCURLY
95713 };
95714
95715 DUK_INTERNAL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out) {
95716         duk_small_uint_t len;
95717         duk_small_uint_t mode;
95718         duk_small_uint_t t;
95719         duk_small_uint_t i;
95720
95721         len = duk_bd_decode(bd, 5);
95722         if (len == 31) {
95723                 len = duk_bd_decode(bd, 8);  /* Support up to 256 bytes; rare. */
95724         }
95725
95726         mode = 32;  /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
95727         for (i = 0; i < len; i++) {
95728                 t = duk_bd_decode(bd, 5);
95729                 if (t < DUK__BITPACK_LETTER_LIMIT) {
95730                         t = t + DUK_ASC_UC_A + mode;
95731                 } else if (t == DUK__BITPACK_LOOKUP1) {
95732                         t = duk__bitpacked_lookup[duk_bd_decode(bd, 3)];
95733                 } else if (t == DUK__BITPACK_LOOKUP2) {
95734                         t = duk__bitpacked_lookup[8 + duk_bd_decode(bd, 3)];
95735                 } else if (t == DUK__BITPACK_SWITCH1) {
95736                         t = duk_bd_decode(bd, 5);
95737                         DUK_ASSERT_DISABLE(t >= 0);  /* unsigned */
95738                         DUK_ASSERT(t <= 25);
95739                         t = t + DUK_ASC_UC_A + (mode ^ 32);
95740                 } else if (t == DUK__BITPACK_SWITCH) {
95741                         mode = mode ^ 32;
95742                         t = duk_bd_decode(bd, 5);
95743                         DUK_ASSERT_DISABLE(t >= 0);
95744                         DUK_ASSERT(t <= 25);
95745                         t = t + DUK_ASC_UC_A + mode;
95746                 } else if (t == DUK__BITPACK_EIGHTBIT) {
95747                         t = duk_bd_decode(bd, 8);
95748                 }
95749                 out[i] = (duk_uint8_t) t;
95750         }
95751
95752         return len;
95753 }
95754
95755 /* automatic undefs */
95756 #undef DUK__BITPACK_EIGHTBIT
95757 #undef DUK__BITPACK_LETTER_LIMIT
95758 #undef DUK__BITPACK_LOOKUP1
95759 #undef DUK__BITPACK_LOOKUP2
95760 #undef DUK__BITPACK_SWITCH
95761 #undef DUK__BITPACK_SWITCH1
95762 #undef DUK__BITPACK_UNUSED1
95763 #line 1 "duk_util_bitencoder.c"
95764 /*
95765  *  Bitstream encoder.
95766  */
95767
95768 /* #include duk_internal.h -> already included */
95769
95770 DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) {
95771         duk_uint8_t tmp;
95772
95773         DUK_ASSERT(ctx != NULL);
95774         DUK_ASSERT(ctx->currbits < 8);
95775
95776         /* This limitation would be fixable but adds unnecessary complexity. */
95777         DUK_ASSERT(bits >= 1 && bits <= 24);
95778
95779         ctx->currval = (ctx->currval << bits) | data;
95780         ctx->currbits += bits;
95781
95782         while (ctx->currbits >= 8) {
95783                 if (ctx->offset < ctx->length) {
95784                         tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff);
95785                         ctx->data[ctx->offset++] = tmp;
95786                 } else {
95787                         /* If buffer has been exhausted, truncate bitstream */
95788                         ctx->truncated = 1;
95789                 }
95790
95791                 ctx->currbits -= 8;
95792         }
95793 }
95794
95795 DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) {
95796         duk_small_int_t npad;
95797
95798         DUK_ASSERT(ctx != NULL);
95799         DUK_ASSERT(ctx->currbits < 8);
95800
95801         npad = (duk_small_int_t) (8 - ctx->currbits);
95802         if (npad > 0) {
95803                 duk_be_encode(ctx, 0, npad);
95804         }
95805         DUK_ASSERT(ctx->currbits == 0);
95806 }
95807 #line 1 "duk_util_bufwriter.c"
95808 /*
95809  *  Fast buffer writer with slack management.
95810  */
95811
95812 /* #include duk_internal.h -> already included */
95813
95814 /* XXX: Avoid duk_{memcmp,memmove}_unsafe() by imposing a minimum length of
95815  * >0 for the underlying dynamic buffer.
95816  */
95817
95818 /*
95819  *  Macro support functions (use only macros in calling code)
95820  */
95821
95822 DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t curr_offset, duk_size_t new_length) {
95823         duk_uint8_t *p;
95824
95825         DUK_ASSERT(thr != NULL);
95826         DUK_ASSERT(bw_ctx != NULL);
95827         DUK_UNREF(thr);
95828
95829         /* 'p' might be NULL when the underlying buffer is zero size.  If so,
95830          * the resulting pointers are not used unsafely.
95831          */
95832         p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf);
95833         DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0));
95834         bw_ctx->p = p + curr_offset;
95835         bw_ctx->p_base = p;
95836         bw_ctx->p_limit = p + new_length;
95837 }
95838
95839 DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) {
95840         DUK_ASSERT(thr != NULL);
95841         DUK_ASSERT(bw_ctx != NULL);
95842         DUK_ASSERT(h_buf != NULL);
95843
95844         bw_ctx->buf = h_buf;
95845         duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf));
95846 }
95847
95848 DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) {
95849         DUK_ASSERT(thr != NULL);
95850         DUK_ASSERT(bw_ctx != NULL);
95851
95852         (void) duk_push_dynamic_buffer(thr, buf_size);
95853         bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(thr, -1);
95854         DUK_ASSERT(bw_ctx->buf != NULL);
95855         duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
95856 }
95857
95858 /* Resize target buffer for requested size.  Called by the macro only when the
95859  * fast path test (= there is space) fails.
95860  */
95861 DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz) {
95862         duk_size_t curr_off;
95863         duk_size_t add_sz;
95864         duk_size_t new_sz;
95865
95866         DUK_ASSERT(thr != NULL);
95867         DUK_ASSERT(bw_ctx != NULL);
95868
95869         /* We could do this operation without caller updating bw_ctx->ptr,
95870          * but by writing it back here we can share code better.
95871          */
95872
95873         curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
95874         add_sz = (curr_off >> DUK_BW_SLACK_SHIFT) + DUK_BW_SLACK_ADD;
95875         new_sz = curr_off + sz + add_sz;
95876         if (DUK_UNLIKELY(new_sz < curr_off)) {
95877                 /* overflow */
95878                 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
95879                 DUK_WO_NORETURN(return NULL;);
95880         }
95881 #if 0  /* for manual torture testing: tight allocation, useful with valgrind */
95882         new_sz = curr_off + sz;
95883 #endif
95884
95885         /* This is important to ensure dynamic buffer data pointer is not
95886          * NULL (which is possible if buffer size is zero), which in turn
95887          * causes portability issues with e.g. memmove() and memcpy().
95888          */
95889         DUK_ASSERT(new_sz >= 1);
95890
95891         DUK_DD(DUK_DDPRINT("resize bufferwriter from %ld to %ld (add_sz=%ld)", (long) curr_off, (long) new_sz, (long) add_sz));
95892
95893         duk_hbuffer_resize(thr, bw_ctx->buf, new_sz);
95894         duk__bw_update_ptrs(thr, bw_ctx, curr_off, new_sz);
95895         return bw_ctx->p;
95896 }
95897
95898 /* Make buffer compact, matching current written size. */
95899 DUK_INTERNAL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) {
95900         duk_size_t len;
95901
95902         DUK_ASSERT(thr != NULL);
95903         DUK_ASSERT(bw_ctx != NULL);
95904         DUK_UNREF(thr);
95905
95906         len = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
95907         duk_hbuffer_resize(thr, bw_ctx->buf, len);
95908         duk__bw_update_ptrs(thr, bw_ctx, len, len);
95909 }
95910
95911 DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
95912         duk_uint8_t *p_base;
95913
95914         DUK_ASSERT(thr != NULL);
95915         DUK_ASSERT(bw != NULL);
95916         DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
95917         DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
95918         DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
95919         DUK_UNREF(thr);
95920
95921         p_base = bw->p_base;
95922         duk_memcpy_unsafe((void *) bw->p,
95923                           (const void *) (p_base + src_off),
95924                           (size_t) len);
95925         bw->p += len;
95926 }
95927
95928 DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
95929         DUK_ASSERT(thr != NULL);
95930         DUK_ASSERT(bw != NULL);
95931         DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
95932         DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
95933         DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
95934
95935         DUK_BW_ENSURE(thr, bw, len);
95936         duk_bw_write_raw_slice(thr, bw, src_off, len);
95937 }
95938
95939 DUK_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) {
95940         duk_uint8_t *p_base;
95941         duk_size_t buf_sz, move_sz;
95942
95943         DUK_ASSERT(thr != NULL);
95944         DUK_ASSERT(bw != NULL);
95945         DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
95946         DUK_ASSERT(buf != NULL);
95947         DUK_UNREF(thr);
95948
95949         p_base = bw->p_base;
95950         buf_sz = (duk_size_t) (bw->p - p_base);  /* constrained by maximum buffer size */
95951         move_sz = buf_sz - dst_off;
95952
95953         DUK_ASSERT(p_base != NULL);  /* buffer size is >= 1 */
95954         duk_memmove_unsafe((void *) (p_base + dst_off + len),
95955                            (const void *) (p_base + dst_off),
95956                            (size_t) move_sz);
95957         duk_memcpy_unsafe((void *) (p_base + dst_off),
95958                           (const void *) buf,
95959                           (size_t) len);
95960         bw->p += len;
95961 }
95962
95963 DUK_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) {
95964         DUK_ASSERT(thr != NULL);
95965         DUK_ASSERT(bw != NULL);
95966         DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
95967         DUK_ASSERT(buf != NULL);
95968
95969         DUK_BW_ENSURE(thr, bw, len);
95970         duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len);
95971 }
95972
95973 DUK_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) {
95974         duk_uint8_t *p_base;
95975         duk_size_t buf_sz, move_sz;
95976
95977         DUK_ASSERT(thr != NULL);
95978         DUK_ASSERT(bw != NULL);
95979         DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
95980         DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
95981         DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
95982         DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
95983         DUK_UNREF(thr);
95984
95985         p_base = bw->p_base;
95986
95987         /* Don't support "straddled" source now. */
95988         DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
95989
95990         if (dst_off <= src_off) {
95991                 /* Target is before source.  Source offset is expressed as
95992                  * a "before change" offset.  Account for the memmove.
95993                  */
95994                 src_off += len;
95995         }
95996
95997         buf_sz = (duk_size_t) (bw->p - p_base);
95998         move_sz = buf_sz - dst_off;
95999
96000         DUK_ASSERT(p_base != NULL);  /* buffer size is >= 1 */
96001         duk_memmove_unsafe((void *) (p_base + dst_off + len),
96002                            (const void *) (p_base + dst_off),
96003                            (size_t) move_sz);
96004         duk_memcpy_unsafe((void *) (p_base + dst_off),
96005                           (const void *) (p_base + src_off),
96006                           (size_t) len);
96007         bw->p += len;
96008 }
96009
96010 DUK_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) {
96011         DUK_ASSERT(thr != NULL);
96012         DUK_ASSERT(bw != NULL);
96013         DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
96014         DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
96015         DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
96016         DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
96017
96018         /* Don't support "straddled" source now. */
96019         DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
96020
96021         DUK_BW_ENSURE(thr, bw, len);
96022         duk_bw_insert_raw_slice(thr, bw, dst_off, src_off, len);
96023 }
96024
96025 DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
96026         duk_uint8_t *p_base, *p_dst, *p_src;
96027         duk_size_t buf_sz, move_sz;
96028
96029         DUK_ASSERT(thr != NULL);
96030         DUK_ASSERT(bw != NULL);
96031         DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
96032         DUK_UNREF(thr);
96033
96034         p_base = bw->p_base;
96035         buf_sz = (duk_size_t) (bw->p - p_base);
96036         move_sz = buf_sz - off;
96037         p_dst = p_base + off + len;
96038         p_src = p_base + off;
96039         duk_memmove_unsafe((void *) p_dst, (const void *) p_src, (size_t) move_sz);
96040         return p_src;  /* point to start of 'reserved area' */
96041 }
96042
96043 DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
96044         DUK_ASSERT(thr != NULL);
96045         DUK_ASSERT(bw != NULL);
96046         DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
96047
96048         DUK_BW_ENSURE(thr, bw, len);
96049         return duk_bw_insert_raw_area(thr, bw, off, len);
96050 }
96051
96052 DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
96053         duk_size_t move_sz;
96054
96055         duk_uint8_t *p_base;
96056         duk_uint8_t *p_src;
96057         duk_uint8_t *p_dst;
96058
96059         DUK_ASSERT(thr != NULL);
96060         DUK_ASSERT(bw != NULL);
96061         DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
96062         DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
96063         DUK_ASSERT(off + len <= DUK_BW_GET_SIZE(thr, bw));
96064         DUK_UNREF(thr);
96065
96066         p_base = bw->p_base;
96067         p_dst = p_base + off;
96068         p_src = p_dst + len;
96069         move_sz = (duk_size_t) (bw->p - p_src);
96070         duk_memmove_unsafe((void *) p_dst,
96071                            (const void *) p_src,
96072                            (size_t) move_sz);
96073         bw->p -= len;
96074 }
96075
96076 /*
96077  *  Macro support functions for reading/writing raw data.
96078  *
96079  *  These are done using mempcy to ensure they're valid even for unaligned
96080  *  reads/writes on platforms where alignment counts.  On x86 at least gcc
96081  *  is able to compile these into a bswap+mov.  "Always inline" is used to
96082  *  ensure these macros compile to minimal code.
96083  *
96084  *  Not really bufwriter related, but currently used together.
96085  */
96086
96087 DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p) {
96088         union {
96089                 duk_uint8_t b[2];
96090                 duk_uint16_t x;
96091         } u;
96092
96093         duk_memcpy((void *) u.b, (const void *) (*p), (size_t) 2);
96094         u.x = DUK_NTOH16(u.x);
96095         *p += 2;
96096         return u.x;
96097 }
96098
96099 DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p) {
96100         union {
96101                 duk_uint8_t b[4];
96102                 duk_uint32_t x;
96103         } u;
96104
96105         duk_memcpy((void *) u.b, (const void *) (*p), (size_t) 4);
96106         u.x = DUK_NTOH32(u.x);
96107         *p += 4;
96108         return u.x;
96109 }
96110
96111 DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p) {
96112         duk_double_union du;
96113         union {
96114                 duk_uint8_t b[4];
96115                 duk_uint32_t x;
96116         } u;
96117
96118         duk_memcpy((void *) u.b, (const void *) (*p), (size_t) 4);
96119         u.x = DUK_NTOH32(u.x);
96120         du.ui[DUK_DBL_IDX_UI0] = u.x;
96121         duk_memcpy((void *) u.b, (const void *) (*p + 4), (size_t) 4);
96122         u.x = DUK_NTOH32(u.x);
96123         du.ui[DUK_DBL_IDX_UI1] = u.x;
96124         *p += 8;
96125
96126         return du.d;
96127 }
96128
96129 DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val) {
96130         union {
96131                 duk_uint8_t b[2];
96132                 duk_uint16_t x;
96133         } u;
96134
96135         u.x = DUK_HTON16(val);
96136         duk_memcpy((void *) (*p), (const void *) u.b, (size_t) 2);
96137         *p += 2;
96138 }
96139
96140 DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val) {
96141         union {
96142                 duk_uint8_t b[4];
96143                 duk_uint32_t x;
96144         } u;
96145
96146         u.x = DUK_HTON32(val);
96147         duk_memcpy((void *) (*p), (const void *) u.b, (size_t) 4);
96148         *p += 4;
96149 }
96150
96151 DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val) {
96152         duk_double_union du;
96153         union {
96154                 duk_uint8_t b[4];
96155                 duk_uint32_t x;
96156         } u;
96157
96158         du.d = val;
96159         u.x = du.ui[DUK_DBL_IDX_UI0];
96160         u.x = DUK_HTON32(u.x);
96161         duk_memcpy((void *) (*p), (const void *) u.b, (size_t) 4);
96162         u.x = du.ui[DUK_DBL_IDX_UI1];
96163         u.x = DUK_HTON32(u.x);
96164         duk_memcpy((void *) (*p + 4), (const void *) u.b, (size_t) 4);
96165         *p += 8;
96166 }
96167 #line 1 "duk_util_cast.c"
96168 /*
96169  *  Cast helpers.
96170  *
96171  *  C99+ coercion is challenging portability-wise because out-of-range casts
96172  *  may invoke implementation defined or even undefined behavior.  See e.g.
96173  *  http://blog.frama-c.com/index.php?post/2013/10/09/Overflow-float-integer.
96174  *
96175  *  Provide explicit cast helpers which try to avoid implementation defined
96176  *  or undefined behavior.  These helpers can then be simplified in the vast
96177  *  majority of cases where the implementation defined or undefined behavior
96178  *  is not problematic.
96179  */
96180
96181 /* #include duk_internal.h -> already included */
96182
96183 /* Portable double-to-integer cast which avoids undefined behavior and avoids
96184  * relying on fmin(), fmax(), or other intrinsics.  Out-of-range results are
96185  * not assumed by caller, but here value is clamped, NaN converts to minval.
96186  */
96187 #define DUK__DOUBLE_INT_CAST1(tname,minval,maxval)  do { \
96188                 if (DUK_LIKELY(x >= (duk_double_t) (minval))) { \
96189                         DUK_ASSERT(!DUK_ISNAN(x)); \
96190                         if (DUK_LIKELY(x <= (duk_double_t) (maxval))) { \
96191                                 return (tname) x; \
96192                         } else { \
96193                                 return (tname) (maxval); \
96194                         } \
96195                 } else { \
96196                         /* NaN or below minval.  Since we don't care about the result \
96197                          * for out-of-range values, just return the minimum value for \
96198                          * both. \
96199                          */ \
96200                         return (tname) (minval); \
96201                 } \
96202         } while (0)
96203
96204 /* Rely on specific NaN behavior for duk_double_{fmin,fmax}(): if either
96205  * argument is a NaN, return the second argument.  This avoids a
96206  * NaN-to-integer cast which is undefined behavior.
96207  */
96208 #define DUK__DOUBLE_INT_CAST2(tname,minval,maxval)  do { \
96209                 return (tname) duk_double_fmin(duk_double_fmax(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \
96210         } while (0)
96211
96212 /* Another solution which doesn't need C99+ behavior for fmin() and fmax(). */
96213 #define DUK__DOUBLE_INT_CAST3(tname,minval,maxval)  do { \
96214                 if (DUK_ISNAN(x)) { \
96215                         /* 0 or any other value is fine. */ \
96216                         return (tname) 0; \
96217                 } else \
96218                         return (tname) DUK_FMIN(DUK_FMAX(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \
96219                 } \
96220         } while (0)
96221
96222 /* C99+ solution: relies on specific fmin() and fmax() behavior in C99: if
96223  * one argument is NaN but the other isn't, the non-NaN argument is returned.
96224  * Because the limits are non-NaN values, explicit NaN check is not needed.
96225  * This may not work on all legacy platforms, and also doesn't seem to inline
96226  * the fmin() and fmax() calls (unless one uses -ffast-math which we don't
96227  * support).
96228  */
96229 #define DUK__DOUBLE_INT_CAST4(tname,minval,maxval)  do { \
96230                 return (tname) DUK_FMIN(DUK_FMAX(x, (duk_double_t) (minval)), (duk_double_t) (maxval)); \
96231         } while (0)
96232
96233 DUK_INTERNAL duk_int_t duk_double_to_int_t(duk_double_t x) {
96234 #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
96235         /* Real world solution: almost any practical platform will provide
96236          * an integer value without any guarantees what it is (which is fine).
96237          */
96238         return (duk_int_t) x;
96239 #else
96240         DUK__DOUBLE_INT_CAST1(duk_int_t, DUK_INT_MIN, DUK_INT_MAX);
96241 #endif
96242 }
96243
96244 DUK_INTERNAL duk_uint_t duk_double_to_uint_t(duk_double_t x) {
96245 #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
96246         return (duk_uint_t) x;
96247 #else
96248         DUK__DOUBLE_INT_CAST1(duk_uint_t, DUK_UINT_MIN, DUK_UINT_MAX);
96249 #endif
96250 }
96251
96252 DUK_INTERNAL duk_int32_t duk_double_to_int32_t(duk_double_t x) {
96253 #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
96254         return (duk_int32_t) x;
96255 #else
96256         DUK__DOUBLE_INT_CAST1(duk_int32_t, DUK_INT32_MIN, DUK_INT32_MAX);
96257 #endif
96258 }
96259
96260 DUK_INTERNAL duk_uint32_t duk_double_to_uint32_t(duk_double_t x) {
96261 #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
96262         return (duk_uint32_t) x;
96263 #else
96264         DUK__DOUBLE_INT_CAST1(duk_uint32_t, DUK_UINT32_MIN, DUK_UINT32_MAX);
96265 #endif
96266 }
96267
96268 /* Largest IEEE double that doesn't round to infinity in the default rounding
96269  * mode.  The exact midpoint between (1 - 2^(-24)) * 2^128 and 2^128 rounds to
96270  * infinity, at least on x64.  This number is one double unit below that
96271  * midpoint.  See misc/float_cast.c.
96272  */
96273 #define DUK__FLOAT_ROUND_LIMIT      340282356779733623858607532500980858880.0
96274
96275 /* Maximum IEEE float.  Double-to-float conversion above this would be out of
96276  * range and thus technically undefined behavior.
96277  */
96278 #define DUK__FLOAT_MAX              340282346638528859811704183484516925440.0
96279
96280 DUK_INTERNAL duk_float_t duk_double_to_float_t(duk_double_t x) {
96281         /* Even a double-to-float cast is technically undefined behavior if
96282          * the double is out-of-range.  C99 Section 6.3.1.5:
96283          *
96284          *   If the value being converted is in the range of values that can
96285          *   be represented but cannot be represented exactly, the result is
96286          *   either the nearest higher or nearest lower representable value,
96287          *   chosen in an implementation-defined manner.  If the value being
96288          *   converted is outside the range of values that can be represented,
96289          *   the behavior is undefined.
96290          */
96291 #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
96292         return (duk_float_t) x;
96293 #else
96294         duk_double_t t;
96295
96296         t = DUK_FABS(x);
96297         DUK_ASSERT((DUK_ISNAN(x) && DUK_ISNAN(t)) ||
96298                    (!DUK_ISNAN(x) && !DUK_ISNAN(t)));
96299
96300         if (DUK_LIKELY(t <= DUK__FLOAT_MAX)) {
96301                 /* Standard in-range case, try to get here with a minimum
96302                  * number of checks and branches.
96303                  */
96304                 DUK_ASSERT(!DUK_ISNAN(x));
96305                 return (duk_float_t) x;
96306         } else if (t <= DUK__FLOAT_ROUND_LIMIT) {
96307                 /* Out-of-range, but rounds to min/max float. */
96308                 DUK_ASSERT(!DUK_ISNAN(x));
96309                 if (x < 0.0) {
96310                         return (duk_float_t) -DUK__FLOAT_MAX;
96311                 } else {
96312                         return (duk_float_t) DUK__FLOAT_MAX;
96313                 }
96314         } else if (DUK_ISNAN(x)) {
96315                 /* Assumes double NaN -> float NaN considered "in range". */
96316                 DUK_ASSERT(DUK_ISNAN(x));
96317                 return (duk_float_t) x;
96318         } else {
96319                 /* Out-of-range, rounds to +/- Infinity. */
96320                 if (x < 0.0) {
96321                         return (duk_float_t) -DUK_DOUBLE_INFINITY;
96322                 } else {
96323                         return (duk_float_t) DUK_DOUBLE_INFINITY;
96324                 }
96325         }
96326 #endif
96327 }
96328
96329 /* automatic undefs */
96330 #undef DUK__DOUBLE_INT_CAST1
96331 #undef DUK__DOUBLE_INT_CAST2
96332 #undef DUK__DOUBLE_INT_CAST3
96333 #undef DUK__DOUBLE_INT_CAST4
96334 #undef DUK__FLOAT_MAX
96335 #undef DUK__FLOAT_ROUND_LIMIT
96336 #line 1 "duk_util_double.c"
96337 /*
96338  *  IEEE double helpers.
96339  */
96340
96341 /* #include duk_internal.h -> already included */
96342
96343 DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) {
96344         duk_double_union du;
96345         du.d = x;
96346         return DUK_DBLUNION_IS_ANYINF(&du);
96347 }
96348
96349 DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) {
96350         duk_double_union du;
96351         du.d = x;
96352         return DUK_DBLUNION_IS_POSINF(&du);
96353 }
96354
96355 DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) {
96356         duk_double_union du;
96357         du.d = x;
96358         return DUK_DBLUNION_IS_NEGINF(&du);
96359 }
96360
96361 DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) {
96362         duk_double_union du;
96363         du.d = x;
96364         /* Assumes we're dealing with a Duktape internal NaN which is
96365          * NaN normalized if duk_tval requires it.
96366          */
96367         DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
96368         return DUK_DBLUNION_IS_NAN(&du);
96369 }
96370
96371 DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) {
96372         duk_double_union du;
96373         du.d = x;
96374         /* Assumes we're dealing with a Duktape internal NaN which is
96375          * NaN normalized if duk_tval requires it.
96376          */
96377         DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
96378         return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du);
96379 }
96380
96381 DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) {
96382         duk_double_union du;
96383         du.d = x;
96384         /* If exponent is 0x7FF the argument is either a NaN or an
96385          * infinity.  We don't need to check any other fields.
96386          */
96387 #if defined(DUK_USE_64BIT_OPS)
96388 #if defined(DUK_USE_DOUBLE_ME)
96389         return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000)) == DUK_U64_CONSTANT(0x000000007ff00000);
96390 #else
96391         return (du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000)) == DUK_U64_CONSTANT(0x7ff0000000000000);
96392 #endif
96393 #else
96394         return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL;
96395 #endif
96396 }
96397
96398 DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) {
96399         duk_double_union du;
96400 #if defined(DUK_USE_64BIT_OPS)
96401         duk_uint64_t t;
96402 #else
96403         duk_uint32_t t;
96404 #endif
96405         du.d = x;
96406 #if defined(DUK_USE_64BIT_OPS)
96407 #if defined(DUK_USE_DOUBLE_ME)
96408         t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x000000007ff00000);
96409         if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
96410                 t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x0000000080000000);
96411                 return t == 0;
96412         }
96413         if (t == DUK_U64_CONSTANT(0x000000007ff00000)) {
96414                 return 1;
96415         }
96416 #else
96417         t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x7ff0000000000000);
96418         if (t == DUK_U64_CONSTANT(0x0000000000000000)) {
96419                 t = du.ull[DUK_DBL_IDX_ULL0] & DUK_U64_CONSTANT(0x8000000000000000);
96420                 return t == 0;
96421         }
96422         if (t == DUK_U64_CONSTANT(0x7ff0000000000000)) {
96423                 return 1;
96424         }
96425 #endif
96426 #else
96427         t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL;
96428         if (t == 0x00000000UL) {
96429                 return DUK_DBLUNION_IS_ANYZERO(&du);
96430         }
96431         if (t == 0x7ff00000UL) {
96432                 return 1;
96433         }
96434 #endif
96435         return 0;
96436 }
96437
96438 DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) {
96439         duk_double_union du;
96440         du.d = x;
96441         return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du);
96442 }
96443
96444 DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) {
96445         /* XXX: optimize */
96446         duk_small_uint_t s = duk_double_signbit(x);
96447         x = DUK_FLOOR(DUK_FABS(x));  /* truncate towards zero */
96448         if (s) {
96449                 x = -x;
96450         }
96451         return x;
96452 }
96453
96454 DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) {
96455         duk_double_union du1;
96456         duk_double_union du2;
96457         du1.d = x;
96458         du2.d = y;
96459
96460         return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0);
96461 }
96462
96463 DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) {
96464         /* Doesn't replicate fmin() behavior exactly: for fmin() if one
96465          * argument is a NaN, the other argument should be returned.
96466          * Duktape doesn't rely on this behavior so the replacement can
96467          * be simplified.
96468          */
96469         return (x < y ? x : y);
96470 }
96471
96472 DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) {
96473         /* Doesn't replicate fmax() behavior exactly: for fmax() if one
96474          * argument is a NaN, the other argument should be returned.
96475          * Duktape doesn't rely on this behavior so the replacement can
96476          * be simplified.
96477          */
96478         return (x > y ? x : y);
96479 }
96480
96481 DUK_INTERNAL duk_bool_t duk_double_is_finite(duk_double_t x) {
96482         return !duk_double_is_nan_or_inf(x);
96483 }
96484
96485 DUK_INTERNAL duk_bool_t duk_double_is_integer(duk_double_t x) {
96486         if (duk_double_is_nan_or_inf(x)) {
96487                 return 0;
96488         } else {
96489                 return duk_js_tointeger_number(x) == x;
96490         }
96491 }
96492
96493 DUK_INTERNAL duk_bool_t duk_double_is_safe_integer(duk_double_t x) {
96494         /* >>> 2**53-1
96495          * 9007199254740991
96496          */
96497         return duk_double_is_integer(x) && DUK_FABS(x) <= 9007199254740991.0;
96498 }
96499
96500 /* Check whether a duk_double_t is a whole number in the 32-bit range (reject
96501  * negative zero), and if so, return a duk_int32_t.
96502  * For compiler use: don't allow negative zero as it will cause trouble with
96503  * LDINT+LDINTX, positive zero is OK.
96504  */
96505 DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) {
96506         duk_int32_t t;
96507
96508         t = duk_double_to_int32_t(x);
96509         if (!((duk_double_t) t == x)) {
96510                 return 0;
96511         }
96512         if (t == 0) {
96513                 duk_double_union du;
96514                 du.d = x;
96515                 if (DUK_DBLUNION_HAS_SIGNBIT(&du)) {
96516                         return 0;
96517                 }
96518         }
96519         *ival = t;
96520         return 1;
96521 }
96522
96523 /* Check whether a duk_double_t is a whole number in the 32-bit range, and if
96524  * so, return a duk_int32_t.
96525  */
96526 DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
96527         duk_int32_t t;
96528
96529         t = duk_double_to_int32_t(x);
96530         if (!((duk_double_t) t == x)) {
96531                 return 0;
96532         }
96533         *ival = t;
96534         return 1;
96535 }
96536
96537 /* Division: division by zero is undefined behavior (and may in fact trap)
96538  * so it needs special handling for portability.
96539  */
96540
96541 DUK_INTERNAL DUK_INLINE duk_double_t duk_double_div(duk_double_t x, duk_double_t y) {
96542 #if !defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
96543         if (DUK_UNLIKELY(y == 0.0)) {
96544                 /* In C99+ division by zero is undefined behavior so
96545                  * avoid it entirely.  Hopefully the compiler is
96546                  * smart enough to avoid emitting any actual code
96547                  * because almost all practical platforms behave as
96548                  * expected.
96549                  */
96550                 if (x > 0.0) {
96551                         if (DUK_SIGNBIT(y)) {
96552                                 return -DUK_DOUBLE_INFINITY;
96553                         } else {
96554                                 return DUK_DOUBLE_INFINITY;
96555                         }
96556                 } else if (x < 0.0) {
96557                         if (DUK_SIGNBIT(y)) {
96558                                 return DUK_DOUBLE_INFINITY;
96559                         } else {
96560                                 return -DUK_DOUBLE_INFINITY;
96561                         }
96562                 } else {
96563                         /* +/- 0, NaN */
96564                         return DUK_DOUBLE_NAN;
96565                 }
96566         }
96567 #endif
96568
96569         return x / y;
96570 }
96571 #line 1 "duk_util_hashbytes.c"
96572 /*
96573  *  Hash function duk_util_hashbytes().
96574  *
96575  *  Currently, 32-bit MurmurHash2.
96576  *
96577  *  Don't rely on specific hash values; hash function may be endianness
96578  *  dependent, for instance.
96579  */
96580
96581 /* #include duk_internal.h -> already included */
96582
96583 #if defined(DUK_USE_STRHASH_DENSE)
96584 /* 'magic' constants for Murmurhash2 */
96585 #define DUK__MAGIC_M  ((duk_uint32_t) 0x5bd1e995UL)
96586 #define DUK__MAGIC_R  24
96587
96588 DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) {
96589         duk_uint32_t h = seed ^ ((duk_uint32_t) len);
96590
96591         while (len >= 4) {
96592                 /* Portability workaround is required for platforms without
96593                  * unaligned access.  The replacement code emulates little
96594                  * endian access even on big endian architectures, which is
96595                  * OK as long as it is consistent for a build.
96596                  */
96597 #if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS)
96598                 duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
96599 #else
96600                 duk_uint32_t k = ((duk_uint32_t) data[0]) |
96601                                  (((duk_uint32_t) data[1]) << 8) |
96602                                  (((duk_uint32_t) data[2]) << 16) |
96603                                  (((duk_uint32_t) data[3]) << 24);
96604 #endif
96605
96606                 k *= DUK__MAGIC_M;
96607                 k ^= k >> DUK__MAGIC_R;
96608                 k *= DUK__MAGIC_M;
96609                 h *= DUK__MAGIC_M;
96610                 h ^= k;
96611                 data += 4;
96612                 len -= 4;
96613         }
96614
96615         switch (len) {
96616         case 3: h ^= data[2] << 16;
96617         case 2: h ^= data[1] << 8;
96618         case 1: h ^= data[0];
96619                 h *= DUK__MAGIC_M;
96620         }
96621
96622         h ^= h >> 13;
96623         h *= DUK__MAGIC_M;
96624         h ^= h >> 15;
96625
96626         return h;
96627 }
96628 #endif  /* DUK_USE_STRHASH_DENSE */
96629
96630 /* automatic undefs */
96631 #undef DUK__MAGIC_M
96632 #undef DUK__MAGIC_R
96633 #line 1 "duk_util_memory.c"
96634 /*
96635  *  Memory utils.
96636  */
96637
96638 /* #include duk_internal.h -> already included */
96639
96640 #if defined(DUK_USE_ALLOW_UNDEFINED_BEHAVIOR)
96641 DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) {
96642         DUK_ASSERT(s1 != NULL || len == 0U);
96643         DUK_ASSERT(s2 != NULL || len == 0U);
96644         return DUK_MEMCMP(s1, s2, (size_t) len);
96645 }
96646
96647 DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) {
96648         DUK_ASSERT(s1 != NULL);
96649         DUK_ASSERT(s2 != NULL);
96650         return DUK_MEMCMP(s1, s2, (size_t) len);
96651 }
96652 #else  /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
96653 DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp_unsafe(const void *s1, const void *s2, duk_size_t len) {
96654         DUK_ASSERT(s1 != NULL || len == 0U);
96655         DUK_ASSERT(s2 != NULL || len == 0U);
96656         if (DUK_UNLIKELY(len == 0U)) {
96657                 return 0;
96658         }
96659         DUK_ASSERT(s1 != NULL);
96660         DUK_ASSERT(s2 != NULL);
96661         return duk_memcmp(s1, s2, len);
96662 }
96663
96664 DUK_INTERNAL DUK_INLINE duk_small_int_t duk_memcmp(const void *s1, const void *s2, duk_size_t len) {
96665         DUK_ASSERT(s1 != NULL);
96666         DUK_ASSERT(s2 != NULL);
96667         return DUK_MEMCMP(s1, s2, (size_t) len);
96668 }
96669 #endif  /* DUK_USE_ALLOW_UNDEFINED_BEHAVIOR */
96670 #line 1 "duk_util_tinyrandom.c"
96671 /*
96672  *  A tiny random number generator used for Math.random() and other internals.
96673  *
96674  *  Default algorithm is xoroshiro128+: http://xoroshiro.di.unimi.it/xoroshiro128plus.c
96675  *  with SplitMix64 seed preparation: http://xorshift.di.unimi.it/splitmix64.c.
96676  *
96677  *  Low memory targets and targets without 64-bit types use a slightly smaller
96678  *  (but slower) algorithm by Adi Shamir:
96679  *  http://www.woodmann.com/forum/archive/index.php/t-3100.html.
96680  *
96681  */
96682
96683 /* #include duk_internal.h -> already included */
96684
96685 #if !defined(DUK_USE_GET_RANDOM_DOUBLE)
96686
96687 #if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
96688 #define DUK__RANDOM_SHAMIR3OP
96689 #else
96690 #define DUK__RANDOM_XOROSHIRO128PLUS
96691 #endif
96692
96693 #if defined(DUK__RANDOM_SHAMIR3OP)
96694 #define DUK__UPDATE_RND(rnd) do { \
96695                 (rnd) += ((rnd) * (rnd)) | 0x05UL; \
96696                 (rnd) = ((rnd) & 0xffffffffUL);       /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
96697         } while (0)
96698
96699 #define DUK__RND_BIT(rnd)  ((rnd) >> 31)  /* only use the highest bit */
96700
96701 DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) {
96702         DUK_UNREF(thr);  /* Nothing now. */
96703 }
96704
96705 DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
96706         duk_double_t t;
96707         duk_small_int_t n;
96708         duk_uint32_t rnd;
96709
96710         rnd = thr->heap->rnd_state;
96711
96712         n = 53;  /* enough to cover the whole mantissa */
96713         t = 0.0;
96714
96715         do {
96716                 DUK__UPDATE_RND(rnd);
96717                 t += DUK__RND_BIT(rnd);
96718                 t /= 2.0;
96719         } while (--n);
96720
96721         thr->heap->rnd_state = rnd;
96722
96723         DUK_ASSERT(t >= (duk_double_t) 0.0);
96724         DUK_ASSERT(t < (duk_double_t) 1.0);
96725
96726         return t;
96727 }
96728 #endif  /* DUK__RANDOM_SHAMIR3OP */
96729
96730 #if defined(DUK__RANDOM_XOROSHIRO128PLUS)
96731 DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_splitmix64(duk_uint64_t *x) {
96732         duk_uint64_t z;
96733         z = (*x += DUK_U64_CONSTANT(0x9E3779B97F4A7C15));
96734         z = (z ^ (z >> 30U)) * DUK_U64_CONSTANT(0xBF58476D1CE4E5B9);
96735         z = (z ^ (z >> 27U)) * DUK_U64_CONSTANT(0x94D049BB133111EB);
96736         return z ^ (z >> 31U);
96737 }
96738
96739 DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_rotl(const duk_uint64_t x, duk_small_uint_t k) {
96740         return (x << k) | (x >> (64U - k));
96741 }
96742
96743 DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__xoroshiro128plus(duk_uint64_t *s) {
96744         duk_uint64_t s0;
96745         duk_uint64_t s1;
96746         duk_uint64_t res;
96747
96748         s0 = s[0];
96749         s1 = s[1];
96750         res = s0 + s1;
96751         s1 ^= s0;
96752         s[0] = duk__rnd_rotl(s0, 55) ^ s1 ^ (s1 << 14U);
96753         s[1] = duk__rnd_rotl(s1, 36);
96754
96755         return res;
96756 }
96757
96758 DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) {
96759         duk_small_uint_t i;
96760         duk_uint64_t x;
96761
96762         /* Mix both halves of the initial seed with SplitMix64.  The intent
96763          * is to ensure that very similar raw seeds (which is usually the case
96764          * because current seed is Date.now()) result in different xoroshiro128+
96765          * seeds.
96766          */
96767         x = thr->heap->rnd_state[0];  /* Only [0] is used as input here. */
96768         for (i = 0; i < 64; i++) {
96769                 thr->heap->rnd_state[i & 0x01] = duk__rnd_splitmix64(&x);  /* Keep last 2 values. */
96770         }
96771 }
96772
96773 DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
96774         duk_uint64_t v;
96775         duk_double_union du;
96776
96777         /* For big and little endian the integer and IEEE double byte order
96778          * is the same so a direct assignment works.  For mixed endian the
96779          * 32-bit parts must be swapped.
96780          */
96781         v = (DUK_U64_CONSTANT(0x3ff) << 52U) | (duk__xoroshiro128plus((duk_uint64_t *) thr->heap->rnd_state) >> 12U);
96782         du.ull[0] = v;
96783 #if defined(DUK_USE_DOUBLE_ME)
96784         do {
96785                 duk_uint32_t tmp;
96786                 tmp = du.ui[0];
96787                 du.ui[0] = du.ui[1];
96788                 du.ui[1] = tmp;
96789         } while (0);
96790 #endif
96791         return du.d - 1.0;
96792 }
96793 #endif  /* DUK__RANDOM_XOROSHIRO128PLUS */
96794
96795 #endif  /* !DUK_USE_GET_RANDOM_DOUBLE */
96796
96797 /* automatic undefs */
96798 #undef DUK__RANDOM_SHAMIR3OP
96799 #undef DUK__RANDOM_XOROSHIRO128PLUS
96800 #undef DUK__RND_BIT
96801 #undef DUK__UPDATE_RND